Back to index

lightning-sunbird  0.9+nobinonly
COtherElements.h
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 /************************************************************************
00040  * MODULE NOTES: 
00041  * @update  gess 04.08.2000
00042  *
00043  *  - CElement::mAutoClose should only be set for tags whose end tag 
00044  *    is optional.
00045  *
00046  *
00047  ************************************************************************/
00048 
00049 #ifndef _COTHERELEMENTS_
00050 #define _COTHERELEMENTS_
00051 
00052 #include "nsDTDUtils.h"
00053 
00054 /************************************************************************
00055   This union is a bitfield which describes the group membership
00056  ************************************************************************/
00057 
00058 
00059 struct CGroupBits {
00060   PRUint32  mHead: 1;     
00061   PRUint32  mHeadMisc: 1;     //script, style, meta, link, object 
00062   PRUint32  mHeadContent: 1;  //title, base
00063   PRUint32  mFontStyle : 1;
00064   PRUint32  mPhrase: 1;
00065   PRUint32  mSpecial: 1;
00066   PRUint32  mFormControl: 1;
00067   PRUint32  mHeading: 1;
00068   PRUint32  mBlock: 1;
00069   PRUint32  mFrame:1;
00070   PRUint32  mList: 1;
00071   PRUint32  mPreformatted: 1;
00072   PRUint32  mTable: 1;
00073   PRUint32  mSelf: 1;
00074   PRUint32  mLeaf: 1;
00075   PRUint32  mWhiteSpace: 1;
00076   PRUint32  mComment: 1;
00077   PRUint32  mTextContainer: 1;
00078   PRUint32  mTopLevel: 1;
00079   PRUint32  mDTDInternal: 1;
00080   PRUint32  mFlowEntity: 1;
00081   PRUint32  mBlockEntity: 1;
00082   PRUint32  mInlineEntity: 1;
00083 };
00084 
00085 union CGroupMembers {
00086   PRUint32    mAllBits;
00087   CGroupBits  mBits;
00088 };
00089 
00090 
00091 inline PRBool ContainsGroup(CGroupMembers& aGroupSet,CGroupMembers& aGroup) {
00092   PRBool result=PR_FALSE;
00093   if(aGroup.mAllBits) {
00094     result=(aGroupSet.mAllBits & aGroup.mAllBits) ? PR_TRUE : PR_FALSE;
00095   }
00096   return result;
00097 }
00098 
00099 inline PRBool ListContainsTag(const eHTMLTags* aTagList,eHTMLTags aTag) {
00100   if(aTagList) {
00101     const eHTMLTags *theNextTag=aTagList;
00102     while(eHTMLTag_unknown!=*theNextTag) {
00103       if(aTag==*theNextTag) {
00104         return PR_TRUE;
00105       }
00106       ++theNextTag;
00107     }
00108   }
00109   return PR_FALSE;
00110 }
00111 
00112 
00113 /**********************************************************
00114   Begin with the baseclass for all elements...
00115  **********************************************************/
00116 class CElement {
00117 public:
00118 
00119     //break this struct out separately so that lame compilers don't gack.
00120   struct CFlags {
00121     PRUint32  mOmitEndTag:1;
00122     PRUint32  mIsContainer:1;
00123     PRUint32  mIsSinkContainer:1;
00124     PRUint32  mDeprecated:1;
00125     PRUint32  mOmitWS:1;
00126   };
00127 
00128   union {
00129     PRUint32  mAllBits;
00130     CFlags    mProperties;
00131   };
00132 
00133   CElement(eHTMLTags aTag=eHTMLTag_unknown) {
00134     mAllBits=0;
00135     mTag=aTag;
00136     mGroup.mAllBits=0;
00137     mContainsGroups.mAllBits=0;
00138     mAutoClose=mIncludeKids=mExcludeKids=0;
00139     mDelegate=eHTMLTag_unknown;
00140   }
00141 
00142   CElement( eHTMLTags aTag,CGroupMembers&  aGroup)  {
00143     mAllBits=0;
00144     mTag=aTag;
00145     mGroup=aGroup;
00146     mContainsGroups.mAllBits=0;
00147     mAutoClose=mIncludeKids=mExcludeKids=0;
00148     mDelegate=eHTMLTag_unknown;
00149   }
00150 
00151   static CGroupMembers& GetEmptyGroup(void) {
00152     static CGroupMembers theGroup={0};
00153     return theGroup;
00154   }
00155 
00156   static void Initialize(CElement& anElement,eHTMLTags aTag){
00157     anElement.mProperties.mIsContainer=0;
00158     anElement.mProperties.mIsSinkContainer=0;
00159     anElement.mTag=aTag;
00160     anElement.mGroup.mAllBits=0;;
00161     anElement.mContainsGroups.mAllBits=0;
00162   }
00163 
00164   static void InitializeLeaf(CElement& anElement,eHTMLTags aTag,CGroupMembers& aGroup,CGroupMembers& aContainsGroups) {
00165     anElement.mProperties.mIsContainer=PR_FALSE;
00166     anElement.mProperties.mIsSinkContainer=PR_FALSE;
00167     anElement.mTag=aTag;
00168     anElement.mGroup.mAllBits=aGroup.mAllBits;
00169     anElement.mContainsGroups.mAllBits=aContainsGroups.mAllBits;
00170   }
00171 
00172   static void Initialize(CElement& anElement,eHTMLTags aTag,CGroupMembers& aGroup,CGroupMembers& aContainsGroups) {
00173     anElement.mProperties.mIsContainer=PR_TRUE;
00174     anElement.mProperties.mIsSinkContainer=PR_TRUE;
00175     anElement.mTag=aTag;
00176     anElement.mGroup.mAllBits=aGroup.mAllBits;
00177     anElement.mContainsGroups.mAllBits=aContainsGroups.mAllBits;
00178   }
00179 
00180   inline CElement*  GetDelegate(void);
00181   inline CElement*  GetDefaultContainerFor(CElement* anElement);
00182 
00183   virtual PRBool    CanContain(CElement* anElement,nsDTDContext* aContext);
00184   virtual PRInt32   FindAutoCloseIndexForStartTag(CElement* anElement,PRInt32 aParentIndex,nsDTDContext* aContext);
00185   virtual PRBool    CanBeClosedByEndTag(CElement* anElement,nsDTDContext* aContext);
00186 
00187     //This tells us whether this tag can potentially close other blocks.
00188     //That DOES NOT mean that this tag is necessarily a block itself (condsider TBODY,TR,TD...)
00189   virtual PRBool    IsBlockCloser(void) {
00190     PRBool result=IsBlockElement(eHTMLTag_body);
00191     if(!result) {
00192       if(IsInlineElement(eHTMLTag_body) ||
00193          mGroup.mBits.mHead || 
00194          mGroup.mBits.mHeadMisc || 
00195          mGroup.mBits.mFormControl || 
00196          mGroup.mBits.mFrame || 
00197          mGroup.mBits.mLeaf || 
00198          mGroup.mBits.mComment || 
00199          mGroup.mBits.mTextContainer || 
00200          mGroup.mBits.mWhiteSpace)
00201          result=PR_FALSE;
00202       else result=PR_TRUE;
00203     }
00204     return result;
00205   }
00206 
00207     //this tells us whether this tag is a block tag within the given parent
00208   virtual PRBool    IsBlockElement(eHTMLTags aParentID);
00209 
00210   //this tells us whether this tag is an inline tag within the given parent
00211   //NOTE: aParentID is currently ignored, but shouldn't be.
00212   virtual PRBool    IsInlineElement(eHTMLTags aParentID);
00213 
00214     //this tells us whether the tag is a container as defined by HTML
00215     //NOTE: aParentID is currently ignored, but shouldn't be.
00216   virtual PRBool    IsContainer(void) {return mProperties.mIsContainer;  }
00217 
00218   //this tells us whether the tag should be opened as a container in the sink (script doesn't, for example).
00219   virtual PRBool    IsSinkContainer(void) { return mProperties.mIsSinkContainer; }
00220 
00221   virtual eHTMLTags GetSkipTarget(void)   {return eHTMLTag_unknown;}
00222   
00223 
00224   virtual nsresult  WillHandleStartToken( CElement* anElement,
00225                                           nsIParserNode* aNode,
00226                                           eHTMLTags aTag,
00227                                           nsDTDContext* aContext,
00228                                           nsIHTMLContentSink* aSink);
00229 
00230   virtual nsresult  HandleStartToken(     nsCParserNode* aNode,
00231                                           eHTMLTags aTag,
00232                                           nsDTDContext* aContext,
00233                                           nsIHTMLContentSink* aSink);
00234 
00235   virtual nsresult  HandleEndToken(nsCParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink);
00236 
00237   virtual nsresult  HandleMisplacedStartToken(nsCParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
00238     nsresult result=NS_OK;
00239     return result;
00240   }
00241 
00242   virtual PRInt32 FindAutoCloseTargetForEndTag(nsCParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink, PRInt32& anIndex) {
00243     PRInt32 result=-1;
00244 
00245     if(mTag!=aTag) {
00246       if(HasOptionalEndTag(mTag) && (0<anIndex)) {
00247         eHTMLTags theGrandParentTag=aContext->TagAt(--anIndex);
00248         CElement *theGrandParent=GetElement(theGrandParentTag);
00249         if(theGrandParent) {
00250           result=theGrandParent->FindAutoCloseTargetForEndTag(aNode,aTag,aContext,aSink,anIndex); //give the parent a chance...
00251         }
00252       }
00253     }
00254     else result=anIndex;
00255 
00256     return result;
00257   }
00258 
00259   virtual nsresult  HandleMisplacedEndToken(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
00260     nsresult result=NS_OK;
00261     return result;
00262   }
00263 
00264   nsresult  AutoGenerateStructure(eHTMLTags *aTagList,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
00265     nsresult  result=NS_OK;
00266 
00267     CStartToken theToken(*aTagList);
00268     nsCParserNode theNode(&theToken, 0 /*stack token*/);
00269     result=OpenContainer(&theNode,*aTagList,aContext,aSink);
00270     if(eHTMLTag_unknown!=*(aTagList+1)) {
00271       AutoGenerateStructure(++aTagList,aContext,aSink);
00272     }
00273     
00274     CEndToken theEndToken(*aTagList--);
00275     nsCParserNode theEndNode(&theEndToken, 0 /*stack token*/);
00276     result=CloseContainer(&theEndNode,*aTagList,aContext,aSink);
00277 
00278     return result;
00279   }
00280         
00281 
00282   /**********************************************************
00283     Call this for each element as it get's opened on the stack
00284    **********************************************************/
00285   virtual nsresult  NotifyOpen(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
00286     return NS_OK;
00287   }
00288 
00289   /**********************************************************
00290     Call this for each element as it get's closed
00291    **********************************************************/
00292   virtual nsresult  NotifyClose(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
00293     return NS_OK;
00294   }
00295 
00296   /**********************************************************
00297    this gets called after each tag is opened in the given context
00298    **********************************************************/
00299   virtual nsresult  OpenContainer(nsIParserNode *aNode,eHTMLTags aTag,nsDTDContext *aContext,nsIHTMLContentSink *aSink) {
00300     return aSink->OpenContainer(*aNode);
00301   }
00302 
00303   /**********************************************************
00304     this gets called after each tag is opened in the given context
00305    **********************************************************/
00306   virtual nsresult  OpenContext(nsCParserNode *aNode,eHTMLTags aTag,nsDTDContext *aContext,nsIHTMLContentSink *aSink) {
00307     aContext->Push(aNode, 0, PR_FALSE);
00308     CElement *theElement = (aTag == mTag) ? this : GetElement(aTag);
00309     theElement->NotifyOpen(aNode, aTag, aContext,aSink);
00310     return NS_OK;
00311   }
00312 
00313   /**********************************************************
00314     this gets called after each tag is opened in the given context
00315    **********************************************************/
00316   virtual nsresult OpenContainerInContext(nsCParserNode *aNode,eHTMLTags aTag,nsDTDContext *aContext,nsIHTMLContentSink *aSink) {    
00317     OpenContext(aNode,aTag,aContext,aSink);
00318     return OpenContainer(aNode,aTag,aContext,aSink);
00319   }
00320 
00321   /**********************************************************
00322     this gets called to close a given tag in the sink
00323    **********************************************************/
00324   virtual nsresult  CloseContainer(nsIParserNode *aNode,eHTMLTags aTag,nsDTDContext *aContext,nsIHTMLContentSink *aSink) {
00325     return aSink->CloseContainer(aTag);
00326   }
00327 
00328   /**********************************************************
00329     this gets called to close a tag in the given context
00330    **********************************************************/
00331   virtual nsresult  CloseContext(nsCParserNode *aNode,eHTMLTags aTag,nsDTDContext *aContext,nsIHTMLContentSink *aSink) {
00332     nsresult result=NS_OK;
00333     nsEntryStack  *theStack=0;
00334     nsCParserNode *theNode=aContext->Pop(theStack);
00335 
00336     CElement *theElement=(aTag==mTag) ? this : GetElement(aTag);
00337     result=theElement->NotifyClose(theNode,aTag,aContext,aSink);
00338 
00339     IF_FREE(aNode, aContext->mNodeAllocator);
00340     return result;
00341   }
00342 
00343   /**********************************************************
00344     this gets called to close a tag in the sink and in the context
00345    **********************************************************/
00346   virtual nsresult CloseContainerInContext(nsCParserNode *aNode,eHTMLTags aTag,nsDTDContext *aContext,nsIHTMLContentSink *aSink) {    
00347     nsresult result=NS_OK;
00348     if(mTag!=aTag) {
00349       CElement *theElement=GetElement(aTag);
00350       return theElement->CloseContainerInContext(aNode,aTag,aContext,aSink);
00351     }
00352     result=CloseContainer(aNode,aTag,aContext,aSink);
00353     CloseContext(aNode,aTag,aContext,aSink);
00354     return result;
00355   }
00356 
00357 
00358   CElement* GetElement(eHTMLTags aTag);
00359 
00360   eHTMLTags       mTag;
00361   eHTMLTags       mDelegate;
00362   CGroupMembers   mGroup;
00363   CGroupMembers   mContainsGroups;
00364   const eHTMLTags       *mIncludeKids;
00365   const eHTMLTags       *mExcludeKids;
00366   const eHTMLTags       *mAutoClose;    //other start tags that close this container
00367 };
00368 
00369 
00370 /**********************************************************
00371   This defines the Special element group
00372  **********************************************************/
00373 class CLeafElement: public CElement {
00374 public:
00375 
00376   static CGroupMembers& GetGroup(void) {
00377     static CGroupMembers theGroup={0};
00378     theGroup.mBits.mLeaf=1;
00379     return theGroup;
00380   }
00381 
00382   static CGroupMembers& GetContainedGroups(void) {
00383     static CGroupMembers theGroups={0};
00384     return theGroups;
00385   }
00386 
00387   static void Initialize(CElement& anElement,eHTMLTags aTag){
00388     CElement::InitializeLeaf(anElement,aTag,GetGroup(),GetContainedGroups());
00389   }
00390 
00391 
00392   CLeafElement(eHTMLTags aTag) : CElement(aTag) {
00393     mProperties.mIsContainer=0;
00394   }
00395 
00396 };
00397 
00398 /**********************************************************
00399   This defines elements that are deprecated
00400  **********************************************************/
00401 class CDeprecatedElement: public CElement {
00402 public:
00403 
00404   static void Initialize(CElement& anElement,eHTMLTags aTag){
00405     CElement::Initialize(anElement,aTag);
00406     anElement.mProperties.mDeprecated=1;
00407   }
00408 
00409   CDeprecatedElement(eHTMLTags aTag) : CElement(aTag) {
00410     CDeprecatedElement::Initialize(*this,aTag);
00411   }
00412 
00413 };
00414 
00415 /**********************************************************
00416   This defines elements that are for use only by the DTD
00417  **********************************************************/
00418 class CInlineElement: public CElement {
00419 public:
00420 
00421   static CGroupMembers& GetGroup(void) {
00422     static CGroupMembers theGroup={0};
00423     theGroup.mBits.mInlineEntity=1;
00424     return theGroup;
00425   }
00426 
00427   static CGroupMembers& GetContainedGroups(void) {
00428     static CGroupMembers theGroup={0};
00429     static PRBool initialized=PR_FALSE;
00430     if(!initialized) {
00431       initialized=PR_TRUE;
00432       theGroup.mBits.mFormControl=1;
00433       theGroup.mBits.mFontStyle =1;
00434       theGroup.mBits.mPhrase=1;
00435       theGroup.mBits.mSpecial=1;
00436       theGroup.mBits.mList=0;  //intentionally remove list from inline group
00437       theGroup.mBits.mPreformatted=0;
00438       theGroup.mBits.mSelf=1;
00439       theGroup.mBits.mLeaf=1;
00440       theGroup.mBits.mWhiteSpace=1;
00441       theGroup.mBits.mComment=1;
00442       theGroup.mBits.mInlineEntity=1;
00443     }
00444     return theGroup;
00445   }
00446 
00447   static void Initialize(CElement& anElement,eHTMLTags aTag){
00448     CElement::Initialize(anElement,aTag,GetGroup(),GetContainedGroups());
00449   }
00450 
00451 
00452 
00453   CInlineElement(eHTMLTags aTag) : CElement(aTag) {
00454     CInlineElement::Initialize(*this,aTag);
00455   }
00456 
00457 };
00458 
00459 /**********************************************************
00460   This defines the Block element group
00461  **********************************************************/
00462 class CBlockElement : public CElement {
00463 public:
00464 
00465   static CGroupMembers& GetGroup(void) {
00466     static CGroupMembers theBlockGroup={0};
00467     theBlockGroup.mBits.mBlock=1;
00468     return theBlockGroup;
00469   }
00470 
00471   /**********************************************************
00472     by default,members of the block group contain inline children
00473    **********************************************************/
00474   static CGroupMembers& GetContainedGroups(PRBool aCanContainSelf = PR_TRUE) {
00475     static CGroupMembers theGroups=CInlineElement::GetContainedGroups();
00476     theGroups.mBits.mSelf=aCanContainSelf;
00477     return theGroups;
00478   }
00479 
00480   /**********************************************************
00481     call this if you want a group that contains only block elements...
00482    **********************************************************/
00483   static CGroupMembers& GetBlockGroupMembers(void) {
00484     static CGroupMembers theGroups={0};
00485     theGroups.mBits.mBlock=1;
00486     theGroups.mBits.mSelf=1;
00487     return theGroups;
00488   }
00489 
00490   static void Initialize(CElement& anElement,eHTMLTags aTag){
00491     CElement::Initialize(anElement,aTag,GetGroup(),GetContainedGroups());
00492   }
00493 
00494   CBlockElement(eHTMLTags aTag) : CElement(aTag) {
00495     CBlockElement::Initialize(*this,aTag);
00496   }
00497 
00498 };
00499 
00500 
00501 /************************************************************
00502   This defines flowEntity elements that contain block+inline
00503  ************************************************************/
00504 class CFlowElement: public CInlineElement {
00505 public:
00506 
00507   static CGroupMembers& GetGroup(void) {
00508     static CGroupMembers theGroup={0};
00509     theGroup.mBits.mFlowEntity=1;
00510     return theGroup;
00511   }
00512 
00513   static CGroupMembers& GetContainedGroups(void) {
00514     static CGroupMembers theGroup={0};
00515     theGroup=CInlineElement::GetContainedGroups();
00516     theGroup.mBits.mBlock=1;
00517     theGroup.mBits.mBlockEntity=1;
00518     return theGroup; 
00519   }
00520 
00521   static void Initialize(CElement& anElement,eHTMLTags aTag){
00522     CElement::Initialize(anElement,aTag,GetGroup(),GetContainedGroups());
00523   }
00524 
00525   CFlowElement(eHTMLTags aTag) : CInlineElement(aTag) {
00526     CFlowElement::Initialize(*this,aTag);
00527   }
00528 
00529 };
00530 
00531 /**********************************************************
00532   This defines the Phrase element group
00533  **********************************************************/
00534 class CPhraseElement: public CElement {
00535 public:
00536 
00537   static CGroupMembers& GetGroup(void) {
00538     static CGroupMembers thePhraseGroup={0};
00539     thePhraseGroup.mBits.mPhrase=1;
00540     return thePhraseGroup;
00541   }
00542 
00543   static CGroupMembers& GetContainedGroups(void) {
00544     static CGroupMembers theGroups=CInlineElement::GetContainedGroups();
00545     return theGroups;
00546   }
00547 
00548   static void Initialize(CElement& anElement,eHTMLTags aTag){
00549     CElement::Initialize(anElement,aTag,GetGroup(),GetContainedGroups());
00550   }
00551 
00552   CPhraseElement(eHTMLTags aTag) : CElement(aTag) {
00553     CPhraseElement::Initialize(*this,aTag);
00554   }
00555 
00556 };
00557 
00558 /**********************************************************
00559   This defines the formcontrol element group
00560  **********************************************************/
00561 class CFormControlElement: public CElement {
00562 public:
00563 
00564   static CGroupMembers& GetGroup(void) {
00565     static CGroupMembers theGroup={0};
00566     theGroup.mBits.mFormControl=1;
00567     return theGroup;
00568   }
00569 
00570   static CGroupMembers& GetContainedGroups(void) {
00571     static CGroupMembers theGroup={0};
00572     theGroup.mBits.mFormControl=1;
00573     theGroup.mBits.mLeaf=1;
00574     theGroup.mBits.mWhiteSpace=1;
00575     return theGroup;
00576   }
00577 
00578   static void Initialize(CElement& anElement,eHTMLTags aTag){
00579     CElement::Initialize(anElement,aTag,GetGroup(),GetContainedGroups());
00580   }
00581 
00582   CFormControlElement(eHTMLTags aTag) : CElement(aTag) {
00583     CFormControlElement::Initialize(*this,aTag);
00584   }
00585 
00586 };
00587 
00588 /**********************************************************
00589   This defines the form element itself
00590  **********************************************************/
00591 class CFormElement: public CBlockElement {
00592 public:
00593 
00594   static void Initialize(CElement& anElement,eHTMLTags aTag){
00595     CElement::Initialize(anElement,aTag,CBlockElement::GetGroup(),CBlockElement::GetBlockGroupMembers());
00596   }
00597 
00598   CFormElement() : CBlockElement(eHTMLTag_form) {
00599     CFormElement::Initialize(*this,eHTMLTag_form);
00600     mContainsGroups.mBits.mSelf=0;
00601     mContainsGroups.mBits.mFormControl=1;
00602   }
00603 
00604   virtual PRBool CanContain(CElement* anElement,nsDTDContext* aContext) {
00605     PRBool result=CElement::CanContain(anElement,aContext);
00606     if((!result) && (aContext->mFlags.mTransitional)) {
00607 
00608       //If we're in transitional mode, then also allow inline elements...
00609         
00610       CGroupMembers& theFlowGroup=CFlowElement::GetContainedGroups();
00611       result=ContainsGroup(theFlowGroup,anElement->mGroup);            
00612     }
00613     return result;
00614   }
00615 
00616   /**********************************************************
00617    this gets called after each tag is opened in the given context
00618    **********************************************************/
00619   virtual nsresult  OpenContainer(nsIParserNode *aNode,eHTMLTags aTag,nsDTDContext *aContext,nsIHTMLContentSink *aSink) {
00620     nsresult result=aSink->OpenForm(*aNode);
00621     return result;
00622   }
00623 
00624 
00625 };
00626 
00627 /**********************************************************
00628   This defines the fontstyle element group
00629  **********************************************************/
00630 class CFontStyleElement: public CElement {
00631 public:
00632 
00633   static CGroupMembers& GetGroup(void) {
00634     static CGroupMembers theGroup={0};
00635     theGroup.mBits.mFontStyle=1;
00636     return theGroup;
00637   }
00638 
00639   static CGroupMembers& GetContainedGroups(void) {
00640     static CGroupMembers theGroups=CInlineElement::GetContainedGroups();
00641     return theGroups;
00642   }
00643 
00644   static void Initialize(CElement& anElement,eHTMLTags aTag){
00645     CElement::Initialize(anElement,aTag,GetGroup(),GetContainedGroups());
00646   }
00647 
00648   CFontStyleElement(eHTMLTags aTag) : CElement(aTag) {
00649     CFontStyleElement::Initialize(*this,aTag);
00650   }
00651 
00652 };
00653 
00654 
00655 /**********************************************************
00656   This defines the special-inline element group
00657  **********************************************************/
00658 class CSpecialElement : public CElement {
00659 public:
00660 
00661   static CGroupMembers& GetGroup(void) {
00662     static CGroupMembers theGroup={0};
00663     theGroup.mBits.mSpecial=1;
00664     return theGroup;
00665   }
00666 
00667   static CGroupMembers& GetContainedGroups(void) {
00668     static CGroupMembers theGroups=CInlineElement::GetContainedGroups();
00669     return theGroups;
00670   }
00671 
00672   static void Initialize(CElement& anElement,eHTMLTags aTag){
00673     CElement::Initialize(anElement,aTag,GetGroup(),GetContainedGroups());
00674   }
00675 
00676   CSpecialElement(eHTMLTags aTag) : CElement(aTag) {
00677     CSpecialElement::Initialize(*this,aTag);
00678   }
00679 
00680 };
00681 
00682 
00683 
00684 /**********************************************************
00685   This defines the Table block itself, not it's children.
00686  **********************************************************/
00687 
00688 class CTableElement: public CElement {
00689 public:
00690 
00691   static CGroupMembers& GetGroup(void) {
00692     static CGroupMembers theTableGroup={0};
00693     theTableGroup.mBits.mTable=1;
00694     return theTableGroup;
00695   }
00696 
00697   static CGroupMembers& GetContainedGroups(void) {
00698     static CGroupMembers theGroups={0};
00699     theGroups.mBits.mTable=1;
00700     return theGroups;
00701   }
00702 
00703   static void Initialize(CElement& anElement,eHTMLTags aTag){
00704     CElement::Initialize(anElement,aTag,GetGroup(),GetContainedGroups());
00705   }
00706 
00707   CTableElement(eHTMLTags aTag=eHTMLTag_table) : CElement(aTag) {
00708     CElement::Initialize(*this,aTag,CBlockElement::GetGroup(),CTableElement::GetContainedGroups());
00709   }
00710 
00711   PRBool CanContain(CElement* anElement,nsDTDContext* aContext) {
00712     PRBool result=PR_FALSE;
00713 
00714     switch(anElement->mTag) {
00715 
00716       case eHTMLTag_caption:
00717         result=(aContext->mTableStates && aContext->mTableStates->CanOpenCaption()); 
00718         break;
00719 
00720       case eHTMLTag_colgroup:
00721         result=(aContext->mTableStates && aContext->mTableStates->CanOpenCols());
00722         break;
00723 
00724       case eHTMLTag_thead:      //nothing to do for these empty tags...      
00725         result=(aContext->mTableStates && aContext->mTableStates->CanOpenTHead());
00726         break;
00727 
00728       case eHTMLTag_tfoot:
00729         result=(aContext->mTableStates && aContext->mTableStates->CanOpenTFoot());
00730         break;
00731 
00732       case eHTMLTag_tr:
00733       case eHTMLTag_th:
00734         result=(aContext->mTableStates && aContext->mTableStates->CanOpenTBody());
00735         break;
00736 
00737       default:
00738         result=CElement::CanContain(anElement,aContext);
00739         break;
00740     }
00741     return result; 
00742   }
00743 
00744   /**********************************************************
00745     Table needs to be notified so it can manage table states.
00746    **********************************************************/
00747   virtual nsresult  NotifyOpen(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
00748     aContext->mTableStates=new CTableState(aContext->mTableStates); //create and prepend a new state
00749     return NS_OK;
00750   }
00751 
00752   /**********************************************************
00753     Table needs to be notified so it can manage table states.
00754    **********************************************************/
00755   virtual nsresult  NotifyClose(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
00756 
00757     nsresult result=NS_OK;
00758     if(aContext->mTableStates) {
00759 
00760       if(!aContext->mTableStates->mHasTBody) {
00761         //so let's open a tbody, a TR and a TD for good measure...
00762 
00763         eHTMLTags theTags[]={eHTMLTag_tbody,eHTMLTag_tr,eHTMLTag_td,eHTMLTag_unknown};
00764         AutoGenerateStructure(theTags,aContext,aSink);
00765       }
00766       
00767       //pop the current state and restore it's predecessor, if any...
00768       CTableState *theState=aContext->mTableStates;      
00769       aContext->mTableStates=theState->mPrevious; 
00770       delete theState;
00771     }
00772     return result;
00773   }
00774  
00775   /**********************************************************
00776     Table handles the opening of it's own children
00777    **********************************************************/
00778   virtual nsresult HandleStartToken(nsCParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
00779     nsresult result=NS_OK;
00780 
00781     switch(aTag) {
00782 
00783       case eHTMLTag_caption:
00784         if(aContext->mTableStates && aContext->mTableStates->CanOpenCaption()) {
00785           result=OpenContainerInContext(aNode,aTag,aContext,aSink);  //force the title onto the stack
00786         }
00787         break;
00788 
00789       case eHTMLTag_col:
00790         result=aSink->AddLeaf(*aNode); 
00791         break;
00792 
00793       case eHTMLTag_colgroup:
00794         if(aContext->mTableStates && aContext->mTableStates->CanOpenCols()) {
00795           result=OpenContainerInContext(aNode,aTag,aContext,aSink);  //force the title onto the stack
00796         }
00797         break;
00798 
00799       case eHTMLTag_thead:      //nothing to do for these empty tags...      
00800         if(aContext->mTableStates && aContext->mTableStates->CanOpenTHead()) {
00801           aContext->mTableStates->mHasTHead=PR_TRUE;
00802           result=OpenContainerInContext(aNode,aTag,aContext,aSink);  //force the title onto the stack
00803         }
00804         break;
00805 
00806       case eHTMLTag_tbody:
00807         aContext->mTableStates->mHasTBody=PR_TRUE;
00808         result=OpenContainerInContext(aNode,aTag,aContext,aSink);  //force the title onto the stack
00809         break;
00810 
00811       case eHTMLTag_tfoot:
00812         if(aContext->mTableStates && aContext->mTableStates->CanOpenTFoot()) {
00813           aContext->mTableStates->mHasTFoot=PR_TRUE;
00814           result=OpenContainerInContext(aNode,aTag,aContext,aSink);  //force the title onto the stack
00815         }
00816         break;
00817 
00818       case eHTMLTag_tr:
00819       case eHTMLTag_th:
00820     
00821         if(aContext->mTableStates) {
00822           if(aContext->mTableStates->CanOpenTBody()) {
00823             CToken* theToken=(CStartToken*)aContext->mTokenAllocator->CreateTokenOfType(eToken_start,eHTMLTag_tbody);
00824             nsCParserNode* theNode=aContext->mNodeAllocator->CreateNode(theToken, 0);
00825 
00826             result=HandleStartToken(theNode,eHTMLTag_tbody,aContext,aSink);
00827           }
00828           if(NS_SUCCEEDED(result)) {
00829             CElement *theElement=GetElement(eHTMLTag_tbody);
00830             if(theElement) {
00831               result=theElement->HandleStartToken(aNode,aTag,aContext,aSink);
00832             }
00833           }
00834         }
00835 
00836         break;
00837 
00838       default:
00839         break;
00840     }
00841     return result; 
00842   }
00843 
00844   /**********************************************************
00845     Table handles the closing of it's own children
00846    **********************************************************/
00847   virtual nsresult HandleEndToken(nsCParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
00848     nsresult result=NS_OK;
00849 
00850     if(aContext->HasOpenContainer(aTag)) {
00851       switch(aTag) {
00852         case eHTMLTag_caption:
00853         case eHTMLTag_col:
00854         case eHTMLTag_colgroup:
00855         case eHTMLTag_tr:
00856         case eHTMLTag_thead:
00857         case eHTMLTag_tfoot:
00858         case eHTMLTag_tbody:      
00859           result=CloseContainerInContext(aNode,aTag,aContext,aSink);  //force the title onto the stack
00860           break;
00861 
00862         default:
00863           break;
00864       } //switch
00865     } //if
00866        
00867 
00868     return result;
00869   }
00870 
00871   /**********************************************************
00872     If you're here, then children below you have optional
00873     end tags, can't deal with the given tag, and want you
00874     to handle it.
00875    **********************************************************/
00876   virtual PRInt32 FindAutoCloseTargetForEndTag(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink, PRInt32& anIndex) {
00877 
00878     // XXXldb This method is completely unused because the |aNode|
00879     // parameter is declared as |nsIParserNode| rather than
00880     // |nsCParserNode| so it doesn't override the member function of
00881     // CElement.
00882     NS_NOTREACHED("This isn't used.  Should it be?");
00883 
00884     PRInt32 result=kNotFound;
00885 
00886     switch(aTag) {
00887       case eHTMLTag_table:
00888       case eHTMLTag_caption:
00889       case eHTMLTag_col:
00890       case eHTMLTag_colgroup:
00891       case eHTMLTag_thead:
00892       case eHTMLTag_tfoot:
00893       case eHTMLTag_tbody:      
00894       case eHTMLTag_tr:      
00895       case eHTMLTag_td:     
00896         {
00897           PRInt32 theTablePos=aContext->LastOf(eHTMLTag_table);
00898           PRInt32 theTagPos=aContext->LastOf(aTag);
00899           if((kNotFound!=theTagPos) && (theTablePos<=theTagPos)) {
00900             result=theTagPos;
00901           }
00902         }
00903         break;
00904 
00905       default:
00906         break;
00907     } //switch
00908 
00909     return result;
00910   }
00911 
00912 };
00913 
00914 /**********************************************************
00915   This defines the Table block itself, not it's children.
00916  **********************************************************/
00917 
00918 class CTableRowElement: public CElement {
00919 public:
00920 
00921   static void Initialize(CElement& anElement,eHTMLTags aTag){
00922     CElement::Initialize(anElement,aTag,CTableElement::GetGroup(),CElement::GetEmptyGroup());
00923     
00924     static eHTMLTags kTRKids[]={eHTMLTag_td,eHTMLTag_th,eHTMLTag_unknown};
00925     anElement.mIncludeKids=kTRKids;
00926   }
00927 
00928   CTableRowElement(eHTMLTags aTag=eHTMLTag_tr) : CElement(aTag) {
00929     CTableRowElement::Initialize(*this,aTag);
00930     mContainsGroups.mBits.mSelf=0;
00931   }
00932 
00933   virtual nsresult  HandleEndTokenForChild(CElement *aChild,nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
00934     nsresult result=NS_OK;
00935     return result;
00936   }
00937 
00938 };
00939 
00940 /**********************************************************
00941   This defines the List element group (ol,ul,dir,menu)
00942  **********************************************************/
00943 class CListElement: public CElement {
00944 public:
00945 
00946   static CGroupMembers& GetGroup(void) {
00947     static CGroupMembers theListGroup={0};
00948     theListGroup.mBits.mList=1;
00949     return theListGroup;
00950   }
00951 
00952   static CGroupMembers& GetContainedGroups(void) {
00953     static CGroupMembers theGroups=CInlineElement::GetContainedGroups();
00954     return theGroups;
00955   }
00956 
00957   static void Initialize(CElement& anElement,eHTMLTags aTag){
00958     CElement::Initialize(anElement,aTag,GetGroup(),GetContainedGroups());
00959   }
00960 
00961   CListElement(eHTMLTags aTag) : CElement(aTag) {
00962     CListElement::Initialize(*this,aTag);
00963   }
00964 
00965 };
00966 
00967 /**********************************************************
00968   This defines the LI element...
00969 
00970   An interesting problem here is that LI normally contains
00971   Block+inline, unless it's inside a MENU or DIR, in which
00972   case it contains only inline.
00973  **********************************************************/
00974 class CLIElement: public CElement {
00975 public:
00976 
00977   CLIElement(eHTMLTags aTag=eHTMLTag_li) : CElement(aTag) {
00978     CFlowElement::Initialize(*this,aTag);
00979     mGroup.mAllBits=0;
00980     mGroup.mBits.mList=1;
00981   }
00982 
00983 };
00984 
00985 /**********************************************************
00986   This defines the heading element group (h1..h6)
00987  **********************************************************/
00988 class CHeadingElement: public CElement {
00989 public:
00990 
00991 
00992   static CGroupMembers& GetGroup(void) {
00993     static CGroupMembers theGroup={0};
00994     theGroup.mBits.mHeading=1;
00995     return theGroup;
00996   }
00997 
00998   static CGroupMembers& GetContainedGroups(void) {
00999     static CGroupMembers theGroups=CInlineElement::GetContainedGroups();
01000     return theGroups;
01001   }
01002 
01003   static void Initialize(CElement& anElement,eHTMLTags aTag){
01004     CElement::Initialize(anElement,aTag,GetGroup(),GetContainedGroups());
01005   }
01006 
01007   CHeadingElement(eHTMLTags aTag) : CElement(aTag) {
01008     CHeadingElement::Initialize(*this,aTag);
01009   }
01010 
01011 };
01012 
01013 /**********************************************************
01014   This defines the tags that relate to frames
01015  **********************************************************/
01016 class CFrameElement: public CElement {
01017 public:
01018 
01019 
01020   static CGroupMembers& GetGroup(void) {
01021     static CGroupMembers theGroup={0};
01022     theGroup.mBits.mFrame=1;
01023     return theGroup;
01024   }
01025 
01026   static void Initialize(CElement& anElement,eHTMLTags aTag){
01027     anElement.mProperties.mIsContainer=1;
01028     anElement.mProperties.mIsSinkContainer=1;
01029     anElement.mTag=aTag;
01030     anElement.mGroup.mAllBits=0;
01031     anElement.mGroup.mBits.mFrame=1;
01032     anElement.mContainsGroups.mAllBits=0;
01033     anElement.mContainsGroups.mBits.mFrame=1;
01034     anElement.mContainsGroups.mBits.mSelf=1;
01035   }
01036 
01037   CFrameElement(eHTMLTags aTag) : CElement(aTag) {
01038     CFrameElement::Initialize(*this,aTag);
01039   }
01040 
01041 };
01042 
01043 
01044 /**********************************************************
01045   This defines elements that are for use only by the DTD
01046  **********************************************************/
01047 class CDTDInternalElement: public CElement {
01048 public:
01049 
01050   static void Initialize(CElement& anElement,eHTMLTags aTag){
01051     anElement.mProperties.mIsContainer=1;
01052     anElement.mTag=aTag;
01053     anElement.mContainsGroups.mAllBits=0;
01054     anElement.mGroup.mBits.mDTDInternal=1;
01055   }
01056 
01057   CDTDInternalElement(eHTMLTags aTag) : CElement(aTag) {
01058     CDTDInternalElement::Initialize(*this,aTag);
01059   }
01060 
01061 
01062 };
01063 
01064 /**********************************************************
01065   Here comes the head element
01066  **********************************************************/
01067 class CHeadElement: public CElement {
01068 public:
01069 
01070   static CGroupMembers& GetGroup(void) {
01071     static CGroupMembers theHeadGroup={0};
01072     theHeadGroup.mBits.mTopLevel=1;
01073     return theHeadGroup;
01074   }
01075 
01076   static CGroupMembers& GetContentGroup(void) {
01077     static CGroupMembers theGroup={0};
01078     theGroup.mBits.mHeadContent=1;
01079     return theGroup;
01080   }
01081 
01082   static CGroupMembers& GetMiscGroup(void) {
01083     static CGroupMembers theGroup={0};
01084     theGroup.mBits.mHeadMisc=1;
01085     return theGroup;
01086   }
01087 
01088   static CGroupMembers& GetContainedGroups(void) {
01089     static CGroupMembers theGroupsContainedByHead={0};
01090     theGroupsContainedByHead.mBits.mHeadMisc=1;
01091     theGroupsContainedByHead.mBits.mHeadContent=1;
01092     return theGroupsContainedByHead;
01093   }
01094 
01095   static void Initialize(CElement& anElement,eHTMLTags aTag){
01096     CElement::Initialize(anElement,aTag,GetGroup(),GetContainedGroups());
01097 
01098     static eHTMLTags kHeadKids[]={eHTMLTag_isindex,eHTMLTag_unknown};
01099 
01100     anElement.mIncludeKids=kHeadKids;
01101   }
01102 
01103   virtual nsresult OpenContext(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
01104 
01105     // XXXldb This method is completely unused because the |aNode|
01106     // parameter is declared as |nsIParserNode| rather than
01107     // |nsCParserNode| so it doesn't override the member function of
01108     // CElement.
01109     NS_NOTREACHED("This isn't used.  Should it be?");
01110 
01111     NS_ASSERTION(aContext!=nsnull,"cannot make a decision without a context");
01112 
01113     nsresult result=NS_OK;
01114     if(aSink && aContext) {
01115       if(aContext->mFlags.mHasOpenHead==PR_FALSE) {
01116         result=aSink->OpenHead(*aNode);
01117         aContext->mFlags.mHasOpenHead=PR_TRUE;
01118       }
01119     }
01120     return result;
01121   }
01122 
01123   virtual nsresult CloseContext(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
01124 
01125     // XXXldb This method is completely unused because the |aNode|
01126     // parameter is declared as |nsIParserNode| rather than
01127     // |nsCParserNode| so it doesn't override the member function of
01128     // CElement.
01129     NS_NOTREACHED("This isn't used.  Should it be?");
01130 
01131     NS_ASSERTION(aContext!=nsnull,"cannot make a decision without a context");
01132 
01133     nsresult result=NS_OK;
01134     if(aSink && aContext) {
01135       if(aContext->mFlags.mHasOpenHead==PR_TRUE) {
01136         result = aSink->CloseHead();
01137         aContext->mFlags.mHasOpenHead=PR_FALSE;
01138       }
01139     }
01140     return result;
01141   }
01142       
01143   CHeadElement(eHTMLTags aTag) : CElement(aTag) {
01144     CHeadElement::Initialize(*this,aTag);
01145   }
01146 };
01147 
01148 
01149 /**********************************************************
01150   This class is for use with title, script, style
01151  **********************************************************/
01152 class CTextContainer : public CElement {
01153 public:
01154 
01155   static CGroupMembers& GetGroup(void) {
01156     static CGroupMembers theGroup={0};
01157     theGroup.mBits.mTextContainer=1; 
01158     return theGroup;
01159   }
01160 
01161   static CGroupMembers& GetContainedGroups(void) {
01162     static CGroupMembers theContainedGroups={0};
01163     theContainedGroups.mBits.mLeaf=1;
01164     return theContainedGroups;
01165   }
01166 
01167   static void Initialize(CElement& anElement,eHTMLTags aTag){
01168     CElement::Initialize(anElement,aTag,GetGroup(),GetContainedGroups());
01169   }
01170 
01171   CTextContainer(eHTMLTags aTag) : CElement(aTag) {
01172     CTextContainer::Initialize(*this,aTag);
01173   }
01174 
01175   virtual ~CTextContainer() {
01176   }
01177 
01178   /**********************************************************
01179     Call this for each element as it get's closed
01180    **********************************************************/
01181   virtual nsresult  NotifyClose(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
01182     nsresult result=NS_OK;
01183     if(aNode) {
01184 #if 0
01185       CStartToken   theToken(aTag);
01186       nsCParserNode theNode(&theToken);
01187       theNode.SetSkippedContent(mText);
01188       result=aSink->AddLeaf(theNode);
01189 #endif
01190       nsCParserNode *theNode=(nsCParserNode*)aNode;
01191       //theNode->SetSkippedContent(mText); XXX why do we need this?
01192       result=aSink->AddLeaf(*theNode);
01193     }
01194     mText.Truncate(0);
01195     return result;
01196   }
01197 
01198   /**********************************************************
01199     Textcontainer handles the opening of it's own children
01200    **********************************************************/
01201   virtual nsresult HandleStartToken(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
01202 
01203     // XXXldb This method is completely unused because the |aNode|
01204     // parameter is declared as |nsIParserNode| rather than
01205     // |nsCParserNode| so it doesn't override the member function of
01206     // CElement.
01207     NS_NOTREACHED("This isn't used.  Should it be?");
01208 
01209     nsresult result=NS_OK;
01210 
01211     switch(aTag) {
01212       case eHTMLTag_text:
01213       case eHTMLTag_whitespace:
01214         mText.Append(aNode->GetText());
01215         break;
01216       default:
01217         break;
01218     }
01219 
01220     return result;
01221   }
01222 
01223   virtual nsresult HandleEndToken(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
01224 
01225     // XXXldb This method is completely unused because the |aNode|
01226     // parameter is declared as |nsIParserNode| rather than
01227     // |nsCParserNode| so it doesn't override the member function of
01228     // CElement.
01229     NS_NOTREACHED("This isn't used.  Should it be?");
01230 
01231     nsresult result=NS_OK;
01232     return result;
01233   }
01234 
01235   nsString  mText;
01236 };
01237 
01238 /**********************************************************
01239   This class is for the title element
01240  **********************************************************/
01241 class CTitleElement : public CTextContainer {
01242 public:
01243 
01244   static void Initialize(CElement& anElement,eHTMLTags aTag){
01245     CTextContainer::Initialize(anElement,aTag);
01246   }
01247 
01248   CTitleElement() : CTextContainer(eHTMLTag_title) {
01249     mGroup.mBits.mHeadMisc=1;
01250   }
01251 
01252   /**********************************************************
01253     Call this for each element as it get's closed
01254    **********************************************************/
01255   virtual nsresult  NotifyClose(nsCParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
01256 
01257     // XXXldb This method is completely unused because the |aNode|
01258     // parameter is declared as |nsCParserNode| rather than
01259     // |nsIParserNode| so it doesn't override the member function of
01260     // CTextContainer.
01261     NS_NOTREACHED("This isn't used.  Should it be?");
01262 
01263     nsresult result=NS_OK;
01264     CElement* theHead=GetElement(eHTMLTag_head);
01265     if(theHead) {
01266       result=theHead->OpenContext(aNode,aTag,aContext,aSink);
01267       if(NS_SUCCEEDED(result)) {
01268         result=aSink->SetTitle(mText);
01269         mText.Truncate(0);
01270         if(NS_SUCCEEDED(result)) {
01271           result=theHead->CloseContext(aNode,aTag,aContext,aSink);
01272         }
01273       }
01274     }
01275     return result;
01276   }
01277 
01278   /**********************************************************
01279     Title handles the opening of it's own children
01280    **********************************************************/
01281   virtual nsresult HandleStartToken(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
01282     nsresult result=NS_OK;
01283 
01284     switch(aTag) {
01285       case eHTMLTag_text:
01286         if(aNode && aNode->GetTokenType()==eToken_entity) {
01287           nsAutoString tmp;
01288           aNode->TranslateToUnicodeStr(tmp);
01289           mText.Append(tmp);
01290           break;
01291         }
01292       case eHTMLTag_whitespace:
01293         mText.Append(aNode->GetText());
01294         break;
01295       default:
01296         break;
01297     }
01298 
01299     return result;
01300   }
01301 
01302 };
01303 
01304 /**********************************************************
01305   This class is for the title element
01306  **********************************************************/
01307 class CTextAreaElement: public CTextContainer {
01308 public:
01309 
01310   CTextAreaElement() : CTextContainer(eHTMLTag_textarea) {
01311     mGroup.mBits.mHeadMisc=1;
01312     mGroup=CFormControlElement::GetGroup();
01313     mProperties.mIsSinkContainer=0;
01314   }
01315 
01316   virtual nsresult HandleStartToken(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
01317     nsresult result=NS_OK;
01318 
01319     switch(aTag) {
01320      case eHTMLTag_text:
01321        if(aNode && aNode->GetTokenType()==eToken_entity) {
01322           nsAutoString tmp;
01323           aNode->TranslateToUnicodeStr(tmp);
01324           mText.Append(tmp);
01325           break;
01326         }
01327       case eHTMLTag_whitespace:
01328       case eHTMLTag_newline:
01329         mText.Append(aNode->GetText());
01330         break;
01331       default:
01332         break;
01333     }
01334 
01335     return result;
01336   }
01337 
01338  
01339 };
01340 
01341 /**********************************************************
01342   This class is for use with style
01343  **********************************************************/
01344 class CStyleElement: public CTextContainer {
01345 public:
01346 
01347   static void Initialize(CElement& anElement,eHTMLTags aTag){
01348     CTextContainer::Initialize(anElement,aTag);
01349   }
01350 
01351   CStyleElement() : CTextContainer(eHTMLTag_style) {
01352     mGroup.mBits.mHeadMisc=1;
01353   }
01354 
01355   /**********************************************************
01356     Call this for each element as it get's closed
01357    **********************************************************/
01358   virtual nsresult  NotifyClose(nsCParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
01359 
01360     // XXXldb This method is completely unused because the |aNode|
01361     // parameter is declared as |nsCParserNode| rather than
01362     // |nsIParserNode| so it doesn't override the member function of
01363     // CTextContainer.
01364     NS_NOTREACHED("This isn't used.  Should it be?");
01365 
01366     nsresult result=NS_OK;
01367     CElement* theHead=GetElement(eHTMLTag_head);
01368     if(theHead) {
01369       result=theHead->OpenContext(aNode,aTag,aContext,aSink);
01370       if(NS_SUCCEEDED(result)) {
01371         result=CTextContainer::NotifyClose(aNode,aTag,aContext,aSink);
01372         mText.Truncate(0);
01373         if(NS_SUCCEEDED(result)) {
01374           result=theHead->CloseContext(aNode,aTag,aContext,aSink);
01375         }
01376       }
01377     }
01378     return result;
01379   }
01380 
01381 };
01382 
01383 /**********************************************************
01384   This class is for use with script
01385  **********************************************************/
01386 class CScriptElement: public CTextContainer {
01387 public:
01388 
01389   static void Initialize(CElement& anElement,eHTMLTags aTag){
01390     CTextContainer::Initialize(anElement,aTag);
01391     anElement.mProperties.mIsSinkContainer=PR_FALSE;
01392   }
01393 
01394   CScriptElement() : CTextContainer(eHTMLTag_script) {
01395     mGroup.mBits.mHeadMisc=1;
01396     mGroup.mBits.mInlineEntity=1;
01397     mGroup.mBits.mSpecial=1;
01398     mProperties.mIsSinkContainer=PR_FALSE;
01399   }
01400 
01401   /**********************************************************
01402     this gets called after each tag is opened in the given context
01403    **********************************************************/
01404   virtual nsresult OpenContainerInContext(nsCParserNode *aNode,eHTMLTags aTag,nsDTDContext *aContext,nsIHTMLContentSink *aSink) {    
01405     OpenContext(aNode,aTag,aContext,aSink);
01406     return NS_OK;
01407   }
01408 
01409   /**********************************************************
01410     this gets called to close a tag in the given context
01411    **********************************************************/
01412   virtual nsresult  CloseContext(nsIParserNode *aNode,eHTMLTags aTag,nsDTDContext *aContext,nsIHTMLContentSink *aSink) {
01413 
01414     // XXXldb This method is completely unused because the |aNode|
01415     // parameter is declared as |nsIParserNode| rather than
01416     // |nsCParserNode| so it doesn't override the member function of
01417     // CElement.
01418     NS_NOTREACHED("This isn't used.  Should it be?");
01419 
01420     nsEntryStack* theStack=0;
01421     nsIParserNode *theNode=aContext->Pop(theStack);
01422 
01423     CElement *theElement=(aTag==mTag) ? this : GetElement(aTag);
01424     theElement->NotifyClose(theNode,aTag,aContext,aSink);
01425 
01426     return NS_OK;
01427   }
01428 
01429   /**********************************************************
01430     Call this for each element as it get's closed
01431    **********************************************************/
01432   virtual nsresult  NotifyClose(nsCParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
01433 
01434     // XXXldb This method is completely unused because the |aNode|
01435     // parameter is declared as |nsCParserNode| rather than
01436     // |nsIParserNode| so it doesn't override the member function of
01437     // CTextContainer.
01438     NS_NOTREACHED("This isn't used.  Should it be?");
01439 
01440     nsresult result=NS_OK;
01441 
01442     if(aContext->HasOpenContainer(eHTMLTag_body)) {
01443       //add the script to the body
01444       result=CTextContainer::NotifyClose(aNode,aTag,aContext,aSink);
01445     }
01446     else {
01447         //add it to the head...
01448       CElement* theHead=GetElement(eHTMLTag_head);
01449       if(theHead) {
01450         result=theHead->OpenContext(aNode,aTag,aContext,aSink);
01451         if(NS_SUCCEEDED(result)) {
01452           result=CTextContainer::NotifyClose(aNode,aTag,aContext,aSink);
01453           if(NS_SUCCEEDED(result)) {
01454             result=theHead->CloseContext(aNode,aTag,aContext,aSink);
01455           }
01456         }
01457       }
01458     }
01459     mText.Truncate(0);
01460     return result;
01461   }
01462 
01463 
01464 };
01465 
01466 /**********************************************************
01467   This defines the preformatted element group, (PRE).
01468  **********************************************************/
01469 class CPreformattedElement: public CBlockElement {
01470 public:
01471 
01472   static void Initialize(CElement& anElement,eHTMLTags aTag){
01473     CBlockElement::Initialize(anElement,aTag);
01474   }
01475 
01476   CPreformattedElement(eHTMLTags aTag) : CBlockElement(aTag) {
01477     mGroup=GetGroup();
01478     mContainsGroups=GetContainedGroups();
01479     mProperties.mIsContainer=1;
01480   }
01481 
01482   /**********************************************************
01483     Pre handles the opening of it's own children
01484    **********************************************************/
01485   virtual nsresult HandleStartToken(nsCParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
01486     nsresult result=CElement::HandleStartToken(aNode,aTag,aContext,aSink);
01487     return result;
01488   }
01489 
01490 
01491   /**********************************************************
01492     Pre handles the closing of it's own children
01493    **********************************************************/
01494   virtual nsresult HandleEndToken(nsCParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
01495     nsresult result=CElement::HandleEndToken(aNode,aTag,aContext,aSink);
01496     return result;
01497   }
01498 
01499 };
01500 
01501 /**********************************************************
01502   This is used for both applet and object elements
01503  **********************************************************/
01504 class CAppletElement: public CSpecialElement {
01505 public:
01506 
01507   static CGroupMembers& GetGroup(void) {
01508     static CGroupMembers theGroup={0};
01509     theGroup.mBits.mSpecial=1;
01510     theGroup.mBits.mBlock=1;
01511     return theGroup;
01512   }
01513 
01514   static CGroupMembers& GetContainedGroups(void) {
01515     return CFlowElement::GetContainedGroups();
01516   }
01517 
01518   static void Initialize(CElement& anElement,eHTMLTags aTag){
01519     CElement::Initialize(anElement,aTag,GetGroup(),GetContainedGroups());
01520 
01521     static eHTMLTags kSpecialKids[]={eHTMLTag_param,eHTMLTag_unknown};
01522     anElement.mIncludeKids=kSpecialKids;
01523     anElement.mProperties.mIsContainer=1;
01524   }
01525 
01526   CAppletElement(eHTMLTags aTag) : CSpecialElement(aTag) {
01527     Initialize(*this,aTag);
01528   }
01529 
01530   /**********************************************************
01531     handles the opening of it's own children
01532    **********************************************************/
01533   virtual nsresult HandleStartToken(nsCParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
01534     nsresult result=NS_OK;
01535     nsIParserNode *theNode=aContext->PeekNode();
01536     if(theNode) {
01537       PRBool  theContentsHaveArrived=theNode->GetGenericState();
01538       switch(aTag) {
01539         case eHTMLTag_param:
01540           if(!theContentsHaveArrived) {
01541             result=CElement::HandleStartToken(aNode,aTag,aContext,aSink);  
01542           }
01543           break;
01544            
01545         case eHTMLTag_newline:
01546         case eHTMLTag_whitespace:
01547           result=CElement::HandleStartToken(aNode,aTag,aContext,aSink);  
01548           break;
01549 
01550         default:
01551           theNode->SetGenericState(PR_TRUE);
01552           result=CElement::HandleStartToken(aNode,aTag,aContext,aSink);  
01553           break;
01554       } //switch
01555     }
01556     return result;
01557   }
01558 
01559 };
01560 
01561 /**********************************************************
01562   This defines the fieldset element...
01563  **********************************************************/
01564 class CFieldsetElement: public CBlockElement {
01565 public:
01566 
01567   static CGroupMembers& GetGroup(void) {
01568     static CGroupMembers theGroup={0};
01569     theGroup.mBits.mBlock=1;
01570     return theGroup;
01571   }
01572 
01573   static CGroupMembers& GetContainedGroups(void) {
01574     return CFlowElement::GetContainedGroups();
01575   }
01576 
01577   static void Initialize(CElement& anElement,eHTMLTags aTag){
01578     CElement::Initialize(anElement,aTag,GetGroup(),GetContainedGroups());
01579   }
01580 
01581   CFieldsetElement() : CBlockElement(eHTMLTag_fieldset) {
01582     mGroup=GetGroup();
01583     mContainsGroups=GetContainedGroups();
01584     mProperties.mIsContainer=1;
01585   }
01586 
01587   /**********************************************************
01588     fieldset  handles the opening of it's own children
01589    **********************************************************/
01590   virtual nsresult HandleStartToken(nsCParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
01591     nsresult result=NS_OK;
01592     nsIParserNode *theNode=aContext->PeekNode();
01593     if(theNode) {
01594       PRBool  theLegendExists=theNode->GetGenericState();
01595       switch(aTag) {
01596         case eHTMLTag_legend:
01597           if(!theLegendExists) {
01598             theNode->SetGenericState(PR_TRUE);
01599             result=OpenContainerInContext(aNode,aTag,aContext,aSink);  //force the title onto the stack
01600           }
01601           break;
01602         default:
01603           if(theLegendExists) {
01604             result=CElement::HandleStartToken(aNode,aTag,aContext,aSink);  //force the title onto the stack
01605           }
01606           break;
01607       } //switch
01608     }
01609     return result;
01610   }
01611 
01612 };
01613 
01614 /**********************************************************
01615   This is for FRAMESET, etc.
01616  **********************************************************/
01617 class CTopLevelElement: public CElement {
01618 public:
01619 
01620 
01621   static CGroupMembers& GetGroup(void) {
01622     static CGroupMembers theGroup={0};
01623     theGroup.mBits.mTopLevel=1;
01624     return theGroup;
01625   }
01626 
01627   static CGroupMembers& GetContainedGroups(void) {
01628     static CGroupMembers theGroup=CFlowElement::GetContainedGroups();
01629     return theGroup;
01630   }
01631 
01632 
01633   static void Initialize(CElement& anElement,eHTMLTags aTag){
01634     CElement::Initialize(anElement,aTag,GetGroup(),GetContainedGroups());
01635   }
01636 
01637   CTopLevelElement(eHTMLTags aTag) : CElement(aTag) {
01638     CTopLevelElement::Initialize(*this,aTag);
01639   }
01640 
01641 
01642   /**********************************************************
01643     Toplevel handles the opening of it's own children
01644    **********************************************************/
01645   virtual nsresult HandleStartToken(  nsCParserNode* aNode,
01646                                       eHTMLTags aTag,
01647                                       nsDTDContext* aContext,
01648                                       nsIHTMLContentSink* aSink) {
01649     nsresult result=NS_OK;
01650 
01651     switch(aTag) {
01652       case eHTMLTag_unknown:
01653       default:
01654         result=CElement::HandleStartToken(aNode,aTag,aContext,aSink);
01655         break;
01656     }//switch
01657 
01658     return result;
01659   }
01660 
01661   /**********************************************************
01662     TopLevel handles the opening of it's own children
01663    **********************************************************/
01664   virtual nsresult HandleEndToken(nsCParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
01665 
01666     nsresult      result=NS_OK;
01667 
01668     switch(aTag) {
01669       case eHTMLTag_html:
01670         if(aContext->HasOpenContainer(aTag)) {
01671           result=aSink->CloseHTML();
01672           CloseContext(aNode,aTag,aContext,aSink);
01673         }
01674         break;
01675 
01676       case eHTMLTag_body:
01677         if(aContext->HasOpenContainer(aTag)) {
01678           result=aSink->CloseBody();
01679           CloseContext(aNode,aTag,aContext,aSink);
01680         }
01681         break;
01682 
01683       case eHTMLTag_frameset:
01684         if(aContext->HasOpenContainer(aTag)) {
01685           result=aSink->OpenFrameset(*aNode); 
01686           CloseContext(aNode,aTag,aContext,aSink);
01687         }
01688         break;
01689 
01690       default:
01691         result=CElement::HandleEndToken(aNode,aTag,aContext,aSink);
01692         break;
01693     }//switch
01694     
01695     return result;
01696   }
01697 
01698 };
01699 
01700 
01701 /**********************************************************
01702   This is for HTML only...
01703  **********************************************************/
01704 class CHTMLElement: public CTopLevelElement{
01705 public:
01706 
01707   static CGroupMembers& GetGroup(void) {
01708     static CGroupMembers theBlockGroup={0};
01709     theBlockGroup.mBits.mTopLevel=1;
01710     return theBlockGroup;
01711   }
01712 
01713   static CGroupMembers& GetContainedGroups(void) {
01714     static CGroupMembers theGroups={0};
01715     theGroups.mBits.mTopLevel=1;
01716     return theGroups;
01717   }
01718 
01719   CHTMLElement(eHTMLTags aTag) : CTopLevelElement(aTag) {   
01720     CElement::Initialize(*this,aTag,CHTMLElement::GetGroup(),CHTMLElement::GetContainedGroups());
01721   }
01722 
01723   /**********************************************************
01724     HTML handles the opening of it's own children
01725    **********************************************************/
01726   nsresult HandleDoctypeDecl( nsIParserNode* aNode,
01727                               eHTMLTags aTag,
01728                               nsDTDContext* aContext,
01729                               nsIHTMLContentSink* aSink) {
01730 
01731     nsCParserNode *theNode=(nsCParserNode*)aNode;
01732     nsresult result=NS_OK;
01733     if(theNode) {
01734       nsAutoString  theStr(theNode->mToken->GetStringValue());
01735       PRInt32   theLen=theStr.Length();
01736       //PRInt32   thePos=theStr.RFindChar(kGreaterThan);
01737 
01738       theStr.Truncate(theLen-1);
01739       theStr.Cut(0,2);
01740   
01741       result = aSink->AddDocTypeDecl(*aNode);
01742     }
01743     return result;
01744   }
01745 
01746   /**********************************************************
01747     HTML handles the opening of it's own children
01748    **********************************************************/
01749   virtual nsresult HandleStartToken(  nsCParserNode* aNode,
01750                                       eHTMLTags aTag,
01751                                       nsDTDContext* aContext,
01752                                       nsIHTMLContentSink* aSink) {
01753     nsresult result=NS_OK;
01754 
01755     switch(aTag) {
01756       case eHTMLTag_doctypeDecl:
01757         result=HandleDoctypeDecl(aNode,aTag,aContext,aSink);
01758         break;
01759 
01760       case eHTMLTag_frameset:
01761         result=aSink->OpenFrameset(*aNode); 
01762         result=OpenContext(aNode,aTag,aContext,aSink);
01763         aContext->mFlags.mHadFrameset=PR_TRUE;
01764         break;
01765 
01766       case eHTMLTag_base: //nothing to do for these empty tags...      
01767       case eHTMLTag_isindex:
01768       case eHTMLTag_link:
01769       case eHTMLTag_meta:
01770         {
01771           CElement* theHead=GetElement(eHTMLTag_head);
01772           if(theHead) {
01773             result=theHead->OpenContext(aNode,aTag,aContext,aSink);
01774             if(NS_SUCCEEDED(result)) {
01775               result=aSink->AddLeaf(*aNode);
01776               if(NS_SUCCEEDED(result)) {
01777                 result=theHead->CloseContext(aNode,aTag,aContext,aSink);
01778               }
01779             }
01780           }
01781         }
01782         break;
01783 
01784       case eHTMLTag_object:
01785         {
01786           CElement* theHead=GetElement(eHTMLTag_head);
01787           if(theHead) {
01788             result=theHead->OpenContext(aNode,aTag,aContext,aSink);
01789             if(NS_SUCCEEDED(result)) {
01790               result=OpenContainerInContext(aNode,aTag,aContext,aSink);
01791             }
01792           }
01793         }
01794         break;
01795 
01796       case eHTMLTag_script:
01797       case eHTMLTag_style:
01798       case eHTMLTag_title:
01799         result=OpenContext(aNode,aTag,aContext,aSink);  //force the title onto the context stack
01800         break;
01801 
01802       case eHTMLTag_newline:
01803       case eHTMLTag_whitespace:
01804       case eHTMLTag_comment:
01805         break;
01806 
01807 
01808       default:
01809         CElement* theBody=GetElement(eHTMLTag_body);
01810         if(theBody) {
01811           CElement *theChildElement=GetElement(aTag);
01812           if(theBody->CanContain(theChildElement,aContext)) {
01813             //let's auto open the body            
01814             
01815             CToken* theToken=(CStartToken*)aContext->mTokenAllocator->CreateTokenOfType(eToken_start,eHTMLTag_body);
01816             nsCParserNode* theNode=aContext->mNodeAllocator->CreateNode(theToken, 0);
01817 
01818             result=theBody->HandleStartToken(theNode,eHTMLTag_body,aContext,aSink);
01819 
01820             if(NS_SUCCEEDED(result)) {
01821               if(eHTMLTag_body==aContext->Last()) {
01822                 result=theBody->HandleStartToken(aNode,aTag,aContext,aSink);
01823               }
01824             }
01825           }
01826         }
01827         //for now, let's drop other elements onto the floor.
01828         break;
01829     }//switch
01830 
01831     return result;
01832   }
01833 
01834   /**********************************************************
01835     HTML handles the closing of it's own children
01836    **********************************************************/
01837   virtual nsresult HandleEndToken(nsCParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
01838     nsresult result=NS_OK;
01839 
01840     switch(aTag) {
01841       case eHTMLTag_body:
01842         aSink->CloseBody();
01843         result=CloseContext(aNode,aTag,aContext,aSink);
01844         break;
01845 
01846       case eHTMLTag_frameset:
01847         aSink->CloseFrameset();
01848         result=CloseContext(aNode,aTag,aContext,aSink);
01849         break;
01850 
01851       case eHTMLTag_object:
01852         result=CloseContainerInContext(aNode,aTag,aContext,aSink);
01853         aSink->CloseHead();
01854         break;
01855 
01856       case eHTMLTag_script:
01857       case eHTMLTag_style:
01858       case eHTMLTag_title:
01859         result=CloseContext(aNode,aTag,aContext,aSink);  //close the title
01860         break;
01861 
01862       case eHTMLTag_unknown:
01863       default:
01864         result=CTopLevelElement::HandleEndToken(aNode,aTag,aContext,aSink);
01865     }
01866     return result;
01867   }
01868 
01869 };
01870 
01871 /**********************************************************
01872   This is for the body element...
01873  **********************************************************/
01874 static const eHTMLTags gBodyKids[] = {eHTMLTag_button, eHTMLTag_del, eHTMLTag_ins, eHTMLTag_map,eHTMLTag_script, eHTMLTag_unknown};
01875 static const eHTMLTags gBodyExcludeKids[] = {eHTMLTag_applet, eHTMLTag_button, eHTMLTag_iframe, eHTMLTag_object, eHTMLTag_unknown};
01876 
01877 class CBodyElement: public CElement {
01878 public:
01879 
01880  
01881   static CGroupMembers& GetGroup(void) {
01882     static CGroupMembers theGroup={0};
01883     theGroup.mBits.mTopLevel=1;
01884     return theGroup;
01885   }
01886 
01887   CBodyElement(eHTMLTags aTag=eHTMLTag_body) : CElement(aTag) {    
01888     CGroupMembers theGroups=CBlockElement::GetBlockGroupMembers();
01889     CElement::Initialize(*this,aTag,CBodyElement::GetGroup(),theGroups);
01890     mIncludeKids=gBodyKids;
01891     mExcludeKids=gBodyExcludeKids;
01892   }
01893 
01894   virtual PRBool CanContain(CElement* anElement,nsDTDContext* aContext) {
01895     PRBool result=CElement::CanContain(anElement,aContext);
01896     if((!result) && (aContext->mFlags.mTransitional)) {
01897       //let's try so additions that are specific to the body tag,
01898       //and only work in transitional mode...
01899         
01900       CGroupMembers& theFlowGroup=CFlowElement::GetContainedGroups();
01901       result=ContainsGroup(theFlowGroup,anElement->mGroup);            
01902     }
01903     return result;
01904   }
01905 
01906    //this gets called after each tag is opened in the given context
01907   virtual nsresult  OpenContainer(nsCParserNode *aNode,eHTMLTags aTag,nsDTDContext *aContext,nsIHTMLContentSink *aSink) {
01908 
01909     // XXXldb This method is completely unused because the |aNode|
01910     // parameter is declared as |nsCParserNode| rather than
01911     // |nsIParserNode| so it doesn't override the member function of
01912     // CElement.
01913     NS_NOTREACHED("This isn't used.  Should it be?");
01914 
01915     nsresult result=NS_OK;
01916     if(mTag==aTag) {
01917       // Close the head before opening a body.
01918       CElement* theHead=GetElement(eHTMLTag_head);
01919       result=theHead->CloseContext(aNode,aTag,aContext,aSink);
01920       if(NS_SUCCEEDED(result)) {
01921         result=aSink->OpenBody(*aNode);
01922       }
01923     }
01924     else result=CElement::OpenContainer(aNode,aTag,aContext,aSink);
01925     return result;
01926   }
01927 
01928   /**********************************************************
01929     this gets called after each tag is opened in the given context
01930    **********************************************************/
01931   virtual nsresult OpenContainerInContext(nsCParserNode *aNode,eHTMLTags aTag,nsDTDContext *aContext,nsIHTMLContentSink *aSink) {
01932     NS_ASSERTION(aContext!=nsnull,"need a valid context");
01933     nsresult result=NS_OK;
01934     // Since BODY is optional, we might come across more than one BODY!.
01935     // That is, one that's auto opened and one that came from the document itself.
01936     // If that's the case then make sure that we don't open up multiple contexts, however,
01937     // don't forget to inform the sink because it needs to account for the BODY attributes.
01938     if(aContext) {
01939       if(!aContext->mFlags.mHadBody) {
01940         result=OpenContext(aNode,aTag,aContext,aSink);
01941         aContext->mFlags.mHadBody=PR_TRUE;
01942       }
01943     }
01944     return (NS_SUCCEEDED(result))? OpenContainer(aNode,aTag,aContext,aSink):result;
01945   }
01946 
01947   /**********************************************************
01948     Body handles the opening of it's own children
01949    **********************************************************/
01950   virtual nsresult HandleStartToken(  nsCParserNode* aNode,
01951                                       eHTMLTags aTag,
01952                                       nsDTDContext* aContext,
01953                                       nsIHTMLContentSink* aSink) {
01954     //for now, let's drop other elements onto the floor.
01955 
01956     nsresult result=CElement::HandleStartToken(aNode,aTag,aContext,aSink);
01957 
01958     if(NS_SUCCEEDED(result)) {
01959       if(aNode) {
01960         nsCParserNode*  theNode=(nsCParserNode*)aNode;
01961         eHTMLTokenTypes theType=eHTMLTokenTypes(theNode->GetTokenType());
01962         if(theType==eToken_start) {
01963           CStartToken *theToken=(CStartToken*)theNode->mToken;
01964           if(theToken && theToken->IsEmpty() && (aTag==aContext->Last())){
01965             result=CElement::HandleEndToken(aNode,aTag,aContext,aSink);
01966           }
01967         }
01968       }
01969     }
01970 
01971     return result;
01972   }
01973 
01974   /**********************************************************
01975     Body doesnt really need to handle it's own kids, but it's
01976     a really convenient break point for debugging purposes.
01977    **********************************************************/
01978   virtual nsresult HandleEndToken(nsCParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
01979     nsresult result=NS_OK;
01980     switch(aTag) {
01981       case eHTMLTag_script:
01982         result=CloseContext(aNode,aTag,aContext,aSink);
01983         break;
01984       default:
01985         result=CElement::HandleEndToken(aNode,aTag,aContext,aSink);
01986     }
01987     return result;
01988   }
01989 
01990   /**********************************************************
01991     Body is the default place where forwarding stops.
01992    **********************************************************/   
01993   virtual nsresult  HandleEndTokenForChild(CElement *aChild,nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
01994     nsresult result=NS_OK;
01995     return result;
01996   }
01997 
01998 protected:
01999 
02000 
02001 };
02002 
02003 
02004 /************************************************************************
02005   This describes each group that each HTML element belongs to
02006  ************************************************************************/
02007 class CElementTable {
02008 public:
02009   enum  {eGroupCount=4};  
02010 
02011   CElementTable() :
02012 
02013     mBodyElement(eHTMLTag_body),
02014     mFramesetElement(eHTMLTag_frameset),
02015     mHTMLElement(eHTMLTag_html),
02016     mScriptElement(),
02017     mStyleElement(),
02018     mTitleElement(),
02019     mTextAreaElement(),
02020     mPreElement(eHTMLTag_pre),
02021     mLIElement(eHTMLTag_li),
02022     mAppletElement(eHTMLTag_applet),
02023     mObjectElement(eHTMLTag_object),
02024     mFieldsetElement(),
02025     mFormElement(),
02026     mHeadElement(eHTMLTag_head)
02027   {
02028     memset(mElements,0,sizeof(mElements));
02029     InitializeElements();
02030 
02031     //DebugDumpBlockElements("test");
02032     //DebugDumpInlineElements("test");
02033 
02034     //DebugDumpContainment("all elements");
02035   }
02036 
02037     //call this to get a ptr to an element prototype...
02038   CElement* GetElement(eHTMLTags aTagID) {
02039     if(aTagID>eHTMLTag_unknown) {
02040       if(aTagID<eHTMLTag_userdefined) {
02041         return mElements[aTagID];
02042       } 
02043     }
02044     return 0;
02045   }
02046 
02047   void InitializeElements();
02048 #ifdef DEBUG
02049   void DebugDumpGroups(CElement* aParent);
02050   void DebugDumpContainment(const char* aTitle);
02051   void DebugDumpContainment(CElement* aParent);
02052 
02053   void DebugDumpInlineElements(const char* aTitle);
02054   void DebugDumpBlockElements(const char* aTitle);
02055 #endif
02056 
02057   CElement* mElements[150];  //add one here for special handling of a given element
02058   CElement  mDfltElements[150];
02059 
02060   CBodyElement      mBodyElement;
02061   CFrameElement     mFramesetElement;
02062   CHTMLElement      mHTMLElement;
02063   CScriptElement    mScriptElement;
02064   CStyleElement     mStyleElement;
02065   CTitleElement     mTitleElement;
02066   CTextAreaElement  mTextAreaElement;
02067   CPreformattedElement mPreElement;
02068   CTableElement     mTableElement;
02069   CLIElement        mLIElement;
02070   CAppletElement    mAppletElement;
02071   CAppletElement    mObjectElement;
02072   CFieldsetElement  mFieldsetElement;
02073   CFormElement      mFormElement;
02074   CHeadElement      mHeadElement;
02075 };
02076 
02077 
02078 static CElementTable *gElementTable = 0;
02079 
02080 static const eHTMLTags kDLKids[]={eHTMLTag_dd,eHTMLTag_dt,eHTMLTag_unknown};
02081 static const eHTMLTags kAutoCloseDD[]={eHTMLTag_dd,eHTMLTag_dt,eHTMLTag_dl,eHTMLTag_unknown};
02082 static const eHTMLTags kButtonExcludeKids[]={ eHTMLTag_a,eHTMLTag_button,eHTMLTag_select,eHTMLTag_textarea,
02083                                         eHTMLTag_input,eHTMLTag_iframe,eHTMLTag_form,eHTMLTag_isindex,
02084                                         eHTMLTag_fieldset,eHTMLTag_unknown};
02085 static const eHTMLTags kColgroupKids[]={eHTMLTag_col,eHTMLTag_unknown};
02086 static const eHTMLTags kDirKids[]={eHTMLTag_li,eHTMLTag_unknown};
02087 static const eHTMLTags kOptionGroupKids[]={eHTMLTag_option,eHTMLTag_unknown};
02088 static const eHTMLTags kFieldsetKids[]={eHTMLTag_legend,eHTMLTag_unknown};
02089 static const eHTMLTags kFormKids[]={eHTMLTag_script,eHTMLTag_unknown};
02090 static const eHTMLTags kLIExcludeKids[]={eHTMLTag_dir,eHTMLTag_menu,eHTMLTag_unknown};
02091 static const eHTMLTags kMapKids[]={eHTMLTag_area,eHTMLTag_unknown};
02092 static const eHTMLTags kPreExcludeKids[]={eHTMLTag_image,eHTMLTag_object,eHTMLTag_applet,
02093                                     eHTMLTag_big,eHTMLTag_small,eHTMLTag_sub,eHTMLTag_sup,
02094                                     eHTMLTag_font,eHTMLTag_basefont,eHTMLTag_unknown};
02095 static const eHTMLTags kSelectKids[]={eHTMLTag_optgroup,eHTMLTag_option,eHTMLTag_unknown};
02096 static const eHTMLTags kBlockQuoteKids[]={eHTMLTag_script,eHTMLTag_unknown};
02097 static const eHTMLTags kFramesetKids[]={eHTMLTag_noframes,eHTMLTag_unknown};
02098 static const eHTMLTags kObjectKids[]={eHTMLTag_param,eHTMLTag_unknown};
02099 static const eHTMLTags kTBodyKids[]={eHTMLTag_tr,eHTMLTag_unknown};
02100 static const eHTMLTags kUnknownKids[]={eHTMLTag_html,eHTMLTag_unknown};
02101 
02102 
02103 inline CElement* CElement::GetElement(eHTMLTags aTag) {
02104   return gElementTable->mElements[aTag];
02105 }
02106 
02107 
02108 /***********************************************************************************
02109   This method is pretty interesting, because it's where the elements all get 
02110   initialized for this elementtable.
02111  ***********************************************************************************/
02112 void CElementTable::InitializeElements() {
02113 
02114   int max=sizeof(mElements)/sizeof(mElements[0]);
02115   int index=0;
02116   for(index=0;index<max;++index){
02117     mElements[index]=&mDfltElements[index];
02118   }
02119 
02120   CSpecialElement::Initialize(      mDfltElements[eHTMLTag_a],          eHTMLTag_a);
02121   mDfltElements[eHTMLTag_a].mContainsGroups.mBits.mSelf=0;
02122 
02123   CPhraseElement::Initialize(       mDfltElements[eHTMLTag_abbr],       eHTMLTag_abbr);
02124   CPhraseElement::Initialize(       mDfltElements[eHTMLTag_acronym],    eHTMLTag_acronym);
02125   CBlockElement::Initialize(        mDfltElements[eHTMLTag_address],    eHTMLTag_address);
02126 
02127   CElement::Initialize(             mDfltElements[eHTMLTag_applet],     eHTMLTag_applet,CSpecialElement::GetGroup(), CFlowElement::GetContainedGroups());
02128 
02129   CElement::Initialize(             mDfltElements[eHTMLTag_area],       eHTMLTag_area);
02130   mDfltElements[eHTMLTag_area].mContainsGroups.mBits.mSelf=0;
02131 
02132   CFontStyleElement::Initialize(    mDfltElements[eHTMLTag_b],          eHTMLTag_b);
02133   CElement::InitializeLeaf(         mDfltElements[eHTMLTag_base],       eHTMLTag_base,  CHeadElement::GetMiscGroup(), CLeafElement::GetContainedGroups());
02134 
02135   CElement::InitializeLeaf(         mDfltElements[eHTMLTag_basefont],   eHTMLTag_basefont, CSpecialElement::GetGroup(), CLeafElement::GetContainedGroups());
02136 
02137   CSpecialElement::Initialize(      mDfltElements[eHTMLTag_bdo],        eHTMLTag_bdo);
02138   CFontStyleElement::Initialize(    mDfltElements[eHTMLTag_big],        eHTMLTag_big);
02139   CDeprecatedElement::Initialize(   mDfltElements[eHTMLTag_bgsound],    eHTMLTag_bgsound);
02140   CElement::Initialize(             mDfltElements[eHTMLTag_blockquote], eHTMLTag_blockquote, CBlockElement::GetGroup(), CBlockElement::GetBlockGroupMembers());
02141   mDfltElements[eHTMLTag_blockquote].mIncludeKids=kBlockQuoteKids;
02142 
02143   //CBodyElement::Initialize(       mDfltElements[eHTMLTag_body],       eHTMLTag_body);
02144   CElement::InitializeLeaf(         mDfltElements[eHTMLTag_br],         eHTMLTag_br,  CSpecialElement::GetGroup(), CLeafElement::GetContainedGroups());
02145 
02146   CElement::Initialize(             mDfltElements[eHTMLTag_button],     eHTMLTag_button,  CFormControlElement::GetGroup(), CFlowElement::GetContainedGroups());
02147   mDfltElements[eHTMLTag_button].mGroup.mBits.mBlock=1;  //make this a member of the block group.
02148   mDfltElements[eHTMLTag_button].mExcludeKids=kButtonExcludeKids;
02149   
02150 
02151   CElement::Initialize(             mDfltElements[eHTMLTag_caption],    eHTMLTag_caption, CTableElement::GetGroup(), CSpecialElement::GetContainedGroups());
02152   mDfltElements[eHTMLTag_tr].mContainsGroups.mBits.mSelf=0;
02153 
02154   CElement::Initialize(             mDfltElements[eHTMLTag_center],     eHTMLTag_center, CBlockElement::GetGroup(), CFlowElement::GetContainedGroups());
02155 
02156   CPhraseElement::Initialize(       mDfltElements[eHTMLTag_cite],       eHTMLTag_cite);
02157   CPhraseElement::Initialize(       mDfltElements[eHTMLTag_code],       eHTMLTag_code);
02158   CElement::Initialize(             mDfltElements[eHTMLTag_col],        eHTMLTag_col, CTableElement::GetGroup(), CLeafElement::GetContainedGroups());
02159   mDfltElements[eHTMLTag_col].mProperties.mIsContainer=0;
02160 
02161   CTableElement::Initialize(        mDfltElements[eHTMLTag_colgroup],   eHTMLTag_colgroup);
02162   mDfltElements[eHTMLTag_colgroup].mContainsGroups.mAllBits=0;
02163   mDfltElements[eHTMLTag_colgroup].mIncludeKids=kColgroupKids;
02164 
02165   CElement::Initialize(             mDfltElements[eHTMLTag_dd],         eHTMLTag_dd,  CElement::GetEmptyGroup(),   CFlowElement::GetContainedGroups());
02166   mDfltElements[eHTMLTag_dd].mAutoClose=kAutoCloseDD;
02167   mDfltElements[eHTMLTag_dd].mContainsGroups.mBits.mSelf=0;
02168 
02169   CElement::Initialize(             mDfltElements[eHTMLTag_del],        eHTMLTag_del, CPhraseElement::GetGroup(),  CFlowElement::GetContainedGroups());
02170   mDfltElements[eHTMLTag_del].mGroup.mBits.mBlock=1;  //make this a member of the block group.
02171 
02172   CElement::Initialize(             mDfltElements[eHTMLTag_dfn],        eHTMLTag_dfn, CPhraseElement::GetGroup(), CInlineElement::GetContainedGroups());
02173   CBlockElement::Initialize(        mDfltElements[eHTMLTag_dir],        eHTMLTag_dir);
02174   mDfltElements[eHTMLTag_dir].mGroup.mBits.mList=1;
02175   mDfltElements[eHTMLTag_dir].mIncludeKids=kDirKids;
02176   mDfltElements[eHTMLTag_dir].mContainsGroups.mAllBits=0;
02177 
02178   CElement::Initialize(             mDfltElements[eHTMLTag_div],        eHTMLTag_div, CBlockElement::GetGroup(),  CFlowElement::GetContainedGroups());
02179  
02180   CBlockElement::Initialize(        mDfltElements[eHTMLTag_dl],         eHTMLTag_dl);  
02181   mDfltElements[eHTMLTag_dl].mContainsGroups.mAllBits=0;
02182   mDfltElements[eHTMLTag_dl].mIncludeKids=kDLKids;
02183 
02184   CElement::Initialize(             mDfltElements[eHTMLTag_dt],         eHTMLTag_dt, CElement::GetEmptyGroup(), CInlineElement::GetContainedGroups());
02185   mDfltElements[eHTMLTag_dt].mContainsGroups.mBits.mLeaf=1;
02186   mDfltElements[eHTMLTag_dt].mAutoClose=kAutoCloseDD;
02187   
02188   CPhraseElement::Initialize(       mDfltElements[eHTMLTag_em],         eHTMLTag_em);
02189   CElement::Initialize(   mDfltElements[eHTMLTag_embed],                eHTMLTag_embed);
02190 
02191   CElement::Initialize(             mDfltElements[eHTMLTag_fieldset],   eHTMLTag_fieldset, CBlockElement::GetGroup(),  CFlowElement::GetContainedGroups());
02192   mDfltElements[eHTMLTag_fieldset].mIncludeKids=kFieldsetKids;
02193 
02194   CSpecialElement::Initialize(      mDfltElements[eHTMLTag_font],       eHTMLTag_font);
02195   CElement::Initialize(             mDfltElements[eHTMLTag_form],       eHTMLTag_form, CBlockElement::GetGroup(), CBlockElement::GetBlockGroupMembers());
02196   mDfltElements[eHTMLTag_form].mContainsGroups.mBits.mFormControl=1;
02197   mDfltElements[eHTMLTag_form].mIncludeKids=kFormKids;
02198 
02199   CElement::Initialize(             mDfltElements[eHTMLTag_frame],      eHTMLTag_frame, CFrameElement::GetGroup(), CLeafElement::GetContainedGroups());
02200   mDfltElements[eHTMLTag_frame].mProperties.mIsContainer=0;
02201 
02202   CFrameElement::Initialize(        mDfltElements[eHTMLTag_frameset],   eHTMLTag_frameset);
02203   mDfltElements[eHTMLTag_frameset].mIncludeKids=kFramesetKids;
02204 
02205   CElement::Initialize(             mDfltElements[eHTMLTag_h1],         eHTMLTag_h1, CBlockElement::GetGroup(), CBlockElement::GetContainedGroups(PR_FALSE));
02206   CElement::Initialize(             mDfltElements[eHTMLTag_h2],         eHTMLTag_h2, CBlockElement::GetGroup(), CBlockElement::GetContainedGroups(PR_FALSE));
02207   CElement::Initialize(             mDfltElements[eHTMLTag_h3],         eHTMLTag_h3, CBlockElement::GetGroup(), CBlockElement::GetContainedGroups(PR_FALSE));
02208   CElement::Initialize(             mDfltElements[eHTMLTag_h4],         eHTMLTag_h4, CBlockElement::GetGroup(), CBlockElement::GetContainedGroups(PR_FALSE));
02209   CElement::Initialize(             mDfltElements[eHTMLTag_h5],         eHTMLTag_h5, CBlockElement::GetGroup(), CBlockElement::GetContainedGroups(PR_FALSE));
02210   CElement::Initialize(             mDfltElements[eHTMLTag_h6],         eHTMLTag_h6, CBlockElement::GetGroup(), CBlockElement::GetContainedGroups(PR_FALSE));
02211 
02212   CElement::InitializeLeaf(         mDfltElements[eHTMLTag_hr],         eHTMLTag_hr,        CBlockElement::GetGroup(), CLeafElement::GetContainedGroups());
02213 
02214 
02215   CElement::Initialize(             mDfltElements[eHTMLTag_head],       eHTMLTag_head,      CHeadElement::GetGroup(), CHeadElement::GetContainedGroups());
02216   // InitializeElement(             mDfltElements[eHTMLTag_head],       eHTMLTag_html,      CTopLevelElement::GetGroup(), CTopLevelElement::GetContainedGroups());
02217 
02218   CFontStyleElement::Initialize(    mDfltElements[eHTMLTag_i],          eHTMLTag_i);
02219   CElement::Initialize(             mDfltElements[eHTMLTag_iframe],     eHTMLTag_iframe,    CSpecialElement::GetGroup(),  CFlowElement::GetContainedGroups());
02220   mDfltElements[eHTMLTag_iframe].mGroup.mBits.mBlock=1;  //make this a member of the block group.
02221 
02222   CElement::InitializeLeaf(         mDfltElements[eHTMLTag_img],        eHTMLTag_img,       CSpecialElement::GetGroup(),  CLeafElement::GetContainedGroups());
02223   CElement::Initialize(             mDfltElements[eHTMLTag_image],      eHTMLTag_image);
02224   CElement::InitializeLeaf(         mDfltElements[eHTMLTag_input],      eHTMLTag_input,     CFormControlElement::GetGroup(),CLeafElement::GetContainedGroups());
02225   CElement::Initialize(             mDfltElements[eHTMLTag_ins],        eHTMLTag_ins,       CPhraseElement::GetGroup(),  CFlowElement::GetContainedGroups());
02226   mDfltElements[eHTMLTag_ins].mGroup.mBits.mBlock=1;  //make this a member of the block group.
02227 
02228   CElement::InitializeLeaf(         mDfltElements[eHTMLTag_isindex],    eHTMLTag_isindex,   CBlockElement::GetGroup(), CLeafElement::GetContainedGroups());
02229 
02230   CPhraseElement::Initialize(       mDfltElements[eHTMLTag_kbd],        eHTMLTag_kbd);
02231   CDeprecatedElement::Initialize(   mDfltElements[eHTMLTag_keygen],     eHTMLTag_keygen);
02232 
02233   CElement::Initialize(             mDfltElements[eHTMLTag_label],      eHTMLTag_label,     CFormControlElement::GetGroup(), CInlineElement::GetContainedGroups());
02234   mDfltElements[eHTMLTag_label].mContainsGroups.mBits.mSelf=0;
02235 
02236   CElement::Initialize(             mDfltElements[eHTMLTag_legend],     eHTMLTag_legend,    CElement::GetEmptyGroup(), CInlineElement::GetContainedGroups());
02237   CElement::Initialize(             mDfltElements[eHTMLTag_li],         eHTMLTag_li,        CListElement::GetGroup(), CFlowElement::GetContainedGroups());
02238   mDfltElements[eHTMLTag_li].mExcludeKids=kLIExcludeKids;
02239   mDfltElements[eHTMLTag_li].mContainsGroups.mBits.mSelf=0;
02240   
02241   CElement::InitializeLeaf(         mDfltElements[eHTMLTag_link],       eHTMLTag_link,  CHeadElement::GetMiscGroup(), CLeafElement::GetContainedGroups());
02242   CElement::Initialize(             mDfltElements[eHTMLTag_listing],    eHTMLTag_listing);
02243 
02244   CElement::Initialize(             mDfltElements[eHTMLTag_map],        eHTMLTag_map,   CSpecialElement::GetGroup(), CBlockElement::GetBlockGroupMembers());
02245   mDfltElements[eHTMLTag_map].mIncludeKids=kMapKids;
02246 
02247   CBlockElement::Initialize(        mDfltElements[eHTMLTag_menu],       eHTMLTag_menu);
02248   mDfltElements[eHTMLTag_menu].mGroup.mBits.mList=1;
02249   mDfltElements[eHTMLTag_menu].mIncludeKids=kDirKids;
02250   mDfltElements[eHTMLTag_menu].mContainsGroups.mAllBits=0;
02251 
02252   CElement::InitializeLeaf(         mDfltElements[eHTMLTag_meta],       eHTMLTag_meta,  CHeadElement::GetMiscGroup(), CLeafElement::GetContainedGroups());
02253 
02254   CElement::Initialize(             mDfltElements[eHTMLTag_multicol],   eHTMLTag_multicol);
02255   CElement::Initialize(             mDfltElements[eHTMLTag_nobr],       eHTMLTag_nobr);
02256   CElement::Initialize(             mDfltElements[eHTMLTag_noembed],    eHTMLTag_noembed);
02257     
02258   CElement::Initialize(             mDfltElements[eHTMLTag_noframes],   eHTMLTag_noframes,  CBlockElement::GetGroup(),  CFlowElement::GetContainedGroups());
02259   CElement::Initialize(             mDfltElements[eHTMLTag_noscript],   eHTMLTag_noscript,  CBlockElement::GetGroup(),  CFlowElement::GetContainedGroups());
02260 
02261   CElement::Initialize(             mDfltElements[eHTMLTag_object],     eHTMLTag_object,    CBlockElement::GetGroup(),  CFlowElement::GetContainedGroups());
02262   mDfltElements[eHTMLTag_object].mGroup.mBits.mBlock=1;  //make this a member of the block group.
02263   mDfltElements[eHTMLTag_object].mGroup.mBits.mHeadMisc=1;
02264   mDfltElements[eHTMLTag_object].mIncludeKids=kObjectKids;
02265 
02266   CBlockElement::Initialize(        mDfltElements[eHTMLTag_ol],         eHTMLTag_ol);
02267   mDfltElements[eHTMLTag_ol].mGroup.mBits.mList=1;
02268   mDfltElements[eHTMLTag_ol].mIncludeKids=kDirKids;
02269   mDfltElements[eHTMLTag_ol].mContainsGroups.mAllBits=0;
02270 
02271   CElement::Initialize(             mDfltElements[eHTMLTag_optgroup],   eHTMLTag_optgroup, CElement::GetEmptyGroup(), CElement::GetEmptyGroup());
02272   mDfltElements[eHTMLTag_optgroup].mContainsGroups.mAllBits=0;
02273   mDfltElements[eHTMLTag_optgroup].mIncludeKids=kOptionGroupKids;
02274 
02275   CElement::Initialize(             mDfltElements[eHTMLTag_option],     eHTMLTag_option, CElement::GetEmptyGroup(), CElement::GetEmptyGroup());
02276   mDfltElements[eHTMLTag_option].mContainsGroups.mAllBits=0;
02277   mDfltElements[eHTMLTag_option].mContainsGroups.mBits.mLeaf=1;
02278 
02279   CElement::Initialize(             mDfltElements[eHTMLTag_p],          eHTMLTag_p, CBlockElement::GetGroup(), CInlineElement::GetContainedGroups());
02280   mDfltElements[eHTMLTag_p].mContainsGroups.mBits.mSelf=0;
02281 
02282   CElement::InitializeLeaf(         mDfltElements[eHTMLTag_param],      eHTMLTag_param, CElement::GetEmptyGroup(), CLeafElement::GetContainedGroups());
02283   CElement::Initialize(             mDfltElements[eHTMLTag_plaintext],  eHTMLTag_plaintext);
02284   CBlockElement::Initialize(        mDfltElements[eHTMLTag_pre],        eHTMLTag_pre);
02285   mDfltElements[eHTMLTag_pre].mExcludeKids=kPreExcludeKids;
02286 
02287   CSpecialElement::Initialize(      mDfltElements[eHTMLTag_q],          eHTMLTag_q);
02288   
02289   CFontStyleElement::Initialize(    mDfltElements[eHTMLTag_s],          eHTMLTag_s);
02290   CPhraseElement::Initialize(       mDfltElements[eHTMLTag_samp],       eHTMLTag_samp );
02291   CSpecialElement::Initialize(      mDfltElements[eHTMLTag_script],     eHTMLTag_script);
02292   mDfltElements[eHTMLTag_script].mGroup.mBits.mBlock=1;  //make this a member of the block group.
02293   mDfltElements[eHTMLTag_script].mGroup.mBits.mHeadMisc=1;
02294 
02295   CFormControlElement::Initialize(  mDfltElements[eHTMLTag_select],     eHTMLTag_select);
02296   mDfltElements[eHTMLTag_select].mContainsGroups.mAllBits=0;
02297   mDfltElements[eHTMLTag_select].mIncludeKids=kSelectKids;
02298 
02299   CElement::Initialize(             mDfltElements[eHTMLTag_server],     eHTMLTag_server);
02300   CFontStyleElement::Initialize(    mDfltElements[eHTMLTag_small],      eHTMLTag_small);
02301   CElement::Initialize(             mDfltElements[eHTMLTag_spacer],     eHTMLTag_spacer);
02302   CSpecialElement::Initialize(      mDfltElements[eHTMLTag_span],       eHTMLTag_span);
02303   CFontStyleElement::Initialize(    mDfltElements[eHTMLTag_strike],     eHTMLTag_strike);
02304   CPhraseElement::Initialize(       mDfltElements[eHTMLTag_strong],     eHTMLTag_strong);
02305   CHeadElement::Initialize(         mDfltElements[eHTMLTag_style],      eHTMLTag_style);
02306   CSpecialElement::Initialize(      mDfltElements[eHTMLTag_sub],        eHTMLTag_sub);
02307   CSpecialElement::Initialize(      mDfltElements[eHTMLTag_sup],        eHTMLTag_sup);
02308 
02309   CElement::Initialize(             mDfltElements[eHTMLTag_table],      eHTMLTag_table,  CBlockElement::GetGroup(), CTableElement::GetContainedGroups());
02310   CElement::Initialize(             mDfltElements[eHTMLTag_tbody],      eHTMLTag_tbody,  CTableElement::GetGroup(), CLeafElement::GetContainedGroups());
02311   mDfltElements[eHTMLTag_tbody].mIncludeKids=kTBodyKids;
02312 
02313   CElement::Initialize(             mDfltElements[eHTMLTag_td],         eHTMLTag_td,      CElement::GetEmptyGroup(), CFlowElement::GetContainedGroups());
02314   mDfltElements[eHTMLTag_td].mContainsGroups.mBits.mSelf=0;
02315 
02316   CElement::Initialize(             mDfltElements[eHTMLTag_textarea],   eHTMLTag_textarea);
02317   
02318   CElement::Initialize(             mDfltElements[eHTMLTag_tfoot],      eHTMLTag_tfoot,   CTableElement::GetGroup(), CLeafElement::GetContainedGroups());
02319   mDfltElements[eHTMLTag_tfoot].mIncludeKids=kTBodyKids;
02320   mDfltElements[eHTMLTag_tfoot].mContainsGroups.mBits.mSelf=0;
02321 
02322   CElement::Initialize(             mDfltElements[eHTMLTag_th],         eHTMLTag_th,      CElement::GetEmptyGroup(), CFlowElement::GetContainedGroups());
02323   mDfltElements[eHTMLTag_th].mContainsGroups.mBits.mSelf=0;
02324 
02325   CElement::Initialize(             mDfltElements[eHTMLTag_thead],      eHTMLTag_thead,   CTableElement::GetGroup(), CLeafElement::GetContainedGroups());
02326   mDfltElements[eHTMLTag_thead].mIncludeKids=kTBodyKids;
02327 
02328   CTableRowElement::Initialize(     mDfltElements[eHTMLTag_tr],         eHTMLTag_tr);
02329   mDfltElements[eHTMLTag_tr].mContainsGroups.mBits.mSelf=0;
02330 
02331   CElement::Initialize(             mDfltElements[eHTMLTag_title],      eHTMLTag_title);
02332 
02333   CFontStyleElement::Initialize(    mDfltElements[eHTMLTag_tt],         eHTMLTag_tt);
02334   CFontStyleElement::Initialize(    mDfltElements[eHTMLTag_u],          eHTMLTag_u);
02335   CBlockElement::Initialize(        mDfltElements[eHTMLTag_ul],         eHTMLTag_ul);
02336   mDfltElements[eHTMLTag_ul].mGroup.mBits.mList=1;
02337   mDfltElements[eHTMLTag_ul].mIncludeKids=kDirKids;
02338   mDfltElements[eHTMLTag_ul].mContainsGroups.mAllBits=0;
02339   
02340   CPhraseElement::Initialize(       mDfltElements[eHTMLTag_var],        eHTMLTag_var);
02341   CElement::Initialize(             mDfltElements[eHTMLTag_wbr],        eHTMLTag_wbr);
02342   CElement::Initialize(             mDfltElements[eHTMLTag_xmp],        eHTMLTag_xmp);
02343 
02344   CLeafElement::Initialize(         mDfltElements[eHTMLTag_text],      eHTMLTag_text);
02345   CLeafElement::Initialize(         mDfltElements[eHTMLTag_comment],   eHTMLTag_comment);
02346   CLeafElement::Initialize(         mDfltElements[eHTMLTag_newline],   eHTMLTag_newline);
02347   CLeafElement::Initialize(         mDfltElements[eHTMLTag_whitespace],eHTMLTag_whitespace);
02348   CLeafElement::Initialize(         mDfltElements[eHTMLTag_unknown],   eHTMLTag_unknown);
02349 
02350   CElement::Initialize(mDfltElements[eHTMLTag_userdefined], 
02351                        eHTMLTag_userdefined, 
02352                        CElement::GetEmptyGroup(),
02353                        CFlowElement::GetContainedGroups()); // allow userdefined tag to contain anything.
02354 
02355   mDfltElements[eHTMLTag_unknown].mIncludeKids=kUnknownKids;
02356 
02357 
02358   /************************************************************
02359      Now let's initialize the elements that we created directly 
02360      to handle special cases.
02361    ************************************************************/
02362 
02363   mElements[eHTMLTag_body]=&mBodyElement;
02364   mElements[eHTMLTag_frameset]=&mFramesetElement;
02365   mElements[eHTMLTag_html]=&mHTMLElement;
02366   mElements[eHTMLTag_script]=&mScriptElement;
02367   mElements[eHTMLTag_style]=&mStyleElement;
02368   mElements[eHTMLTag_title]=&mTitleElement;
02369   mElements[eHTMLTag_textarea]=&mTextAreaElement;
02370   mElements[eHTMLTag_pre]=&mPreElement;
02371   mElements[eHTMLTag_table]=&mTableElement;
02372   mElements[eHTMLTag_li]=&mLIElement;
02373   mElements[eHTMLTag_applet]=&mAppletElement;
02374   mElements[eHTMLTag_object]=&mObjectElement;
02375   mElements[eHTMLTag_fieldset]=&mFieldsetElement;
02376   mElements[eHTMLTag_form]=&mFormElement;
02377   mElements[eHTMLTag_head]=&mHeadElement;
02378 }
02379 
02380 #ifdef DEBUG
02381 void CElementTable::DebugDumpGroups(CElement* aTag){
02382 
02383   const PRUnichar* uctag=nsHTMLTags::GetStringValue(aTag->mTag);
02384 
02385   const char* prefix="     ";
02386   printf("\n\nTag: <%s>\n", NS_ConvertUCS2toUTF8(uctag).get());
02387   printf(prefix);
02388 
02389   if(aTag->IsContainer()) {
02390     if(aTag->mContainsGroups.mBits.mHead)           printf("head ");    
02391     if(aTag->mContainsGroups.mBits.mHeadMisc)       printf("headmisc ");  
02392     if(aTag->mContainsGroups.mBits.mHeadContent)    printf("headcontent ");  
02393     if(aTag->mContainsGroups.mBits.mTable)          printf("table ");
02394     if(aTag->mContainsGroups.mBits.mTextContainer)  printf("text ");
02395     if(aTag->mContainsGroups.mBits.mTopLevel)       printf("toplevel ");
02396     if(aTag->mContainsGroups.mBits.mDTDInternal)    printf("internal ");
02397 
02398     if(aTag->mContainsGroups.mBits.mFlowEntity) {
02399       printf("block inline ");
02400     }
02401     else {
02402 
02403       if (aTag->mContainsGroups.mBits.mBlockEntity)  {
02404         printf("blockEntity ");
02405       }
02406 
02407       if (aTag->mContainsGroups.mBits.mBlock)  {
02408         printf("block ");
02409       }
02410 
02411       if(aTag->mContainsGroups.mBits.mInlineEntity)   {
02412         printf("inline ");
02413       }
02414 
02415       else {
02416 
02417         if(aTag->mContainsGroups.mBits.mFontStyle )     printf("fontstyle ");
02418         if(aTag->mContainsGroups.mBits.mPhrase)         printf("phrase ");
02419         if(aTag->mContainsGroups.mBits.mSpecial)        printf("special ");
02420         if(aTag->mContainsGroups.mBits.mFormControl)    printf("form ");
02421         if(aTag->mContainsGroups.mBits.mHeading)        printf("heading ");  
02422         if(aTag->mContainsGroups.mBits.mFrame)          printf("frame ");
02423         if(aTag->mContainsGroups.mBits.mList)           printf("list ");
02424         if(aTag->mContainsGroups.mBits.mPreformatted)   printf("pre ");
02425         if(aTag->mContainsGroups.mBits.mSelf)           printf("self ");
02426         if(aTag->mContainsGroups.mBits.mLeaf)           printf("leaf ");
02427         if(aTag->mContainsGroups.mBits.mWhiteSpace)     printf("ws ");
02428         if(aTag->mContainsGroups.mBits.mComment)        printf("comment ");
02429       }
02430     
02431     }
02432 
02433     if(aTag->mIncludeKids) {
02434       printf("\n%s",prefix);
02435       const eHTMLTags *theKid=aTag->mIncludeKids;
02436       printf("+ ");
02437       while(eHTMLTag_unknown!=*theKid){
02438         const PRUnichar *t = nsHTMLTags::GetStringValue(*theKid++);
02439         printf("%s ", NS_ConvertUCS2toUTF8(t).get());
02440       }
02441     }
02442 
02443     if(aTag->mExcludeKids) {
02444       printf("\n%s",prefix);
02445       const eHTMLTags *theKid=aTag->mExcludeKids;
02446       printf("- ");
02447       while(eHTMLTag_unknown!=*theKid){
02448         const PRUnichar *t = nsHTMLTags::GetStringValue(*theKid++);
02449         printf("%s ", NS_ConvertUCS2toUTF8(t).get());
02450       }
02451     }
02452 
02453     if(!aTag->mContainsGroups.mBits.mSelf){
02454       printf("\n%s - self",prefix);
02455     }
02456  
02457   }
02458   else {
02459     printf("empty\n");
02460   }
02461 }
02462 
02463 void CElementTable::DebugDumpContainment(CElement* anElement){
02464   const PRUnichar *uctag = nsHTMLTags::GetStringValue(anElement->mTag);
02465   const char* prefix="     ";
02466   printf("\n\nTag: <%s>\n", NS_ConvertUCS2toUTF8(uctag).get());
02467   printf(prefix);
02468 
02469   int count=0;
02470   int i=0;
02471   for(i=0;i<NS_HTML_TAG_MAX;++i){
02472     CElement* theChild=mElements[i];
02473     if(anElement->CanContain(theChild,0)){
02474       const PRUnichar *t = nsHTMLTags::GetStringValue(theChild->mTag);
02475       printf("%s ", NS_ConvertUCS2toUTF8(t).get());
02476       ++count;
02477       if(18==count) {
02478         count=0;
02479         printf("\n%s",prefix);
02480       }
02481     }
02482   }
02483 }
02484 
02485 void CElementTable::DebugDumpInlineElements(const char* aTitle) {
02486   PRInt32   theTagID=eHTMLTag_unknown;
02487   PRBool    result=PR_FALSE;
02488 
02489   printf("Inline Elements -- %s: \n",aTitle);
02490   while(theTagID<=eHTMLTag_userdefined) {
02491     CElement *theTag=GetElement((eHTMLTags)theTagID);
02492     if(theTag) {
02493       result=theTag->IsInlineElement(eHTMLTag_unknown);
02494       if(result) {
02495         const PRUnichar *t = nsHTMLTags::GetStringValue(theTag->mTag);
02496         printf("  %s\n", NS_ConvertUCS2toUTF8(t).get());
02497       }
02498     }
02499     theTagID++;
02500   }
02501 }
02502 
02503 void CElementTable::DebugDumpBlockElements(const char* aTitle) {
02504   PRInt32   theTagID=eHTMLTag_unknown;
02505   PRBool    result=PR_FALSE;
02506 
02507   printf("Block Elements -- %s: \n",aTitle);
02508   while(theTagID<=eHTMLTag_userdefined) {
02509     CElement *theTag=GetElement((eHTMLTags)theTagID);
02510     if(theTag) {
02511       result=theTag->IsBlockElement(eHTMLTag_unknown);
02512       if(result) {
02513         const PRUnichar *theName = nsHTMLTags::GetStringValue(theTag->mTag);
02514         printf("  %s\n", NS_ConvertUCS2toUTF8(theName).get());
02515       }
02516     }
02517     theTagID++;
02518   }
02519 }
02520 
02521 void CElementTable::DebugDumpContainment(const char* aTitle){
02522 #if 0
02523   DebugDumpContainment(mElements[eHTMLTag_head]);
02524   DebugDumpContainment(mElements[eHTMLTag_html]);
02525   DebugDumpContainment(mElements[eHTMLTag_table]);
02526   printf("\n");
02527 #endif
02528 
02529   printf("==================================================\n");
02530   printf("%s\n",aTitle);
02531   printf("==================================================\n");
02532   int i=0;
02533 
02534   for(i=1;i<NS_HTML_TAG_MAX;++i){
02535     DebugDumpContainment(mElements[i]);
02536     //DebugDumpGroups(mElements[i]);
02537   } //for
02538 }
02539 #endif
02540 
02541 /******************************************************************************
02542   Yes, I know it's inconvenient to find this methods here, but it's easier
02543   for the compiler -- and making it's life easier is my top priority.
02544  ******************************************************************************/
02545 PRInt32 CElement::FindAutoCloseIndexForStartTag(CElement* anElement,PRInt32 aParentIndex,nsDTDContext* aContext) {
02546   PRInt32 result=kNotFound;
02547 
02548   if(anElement) {
02549     eHTMLTags theParentTag=aContext->TagAt(aParentIndex);
02550     if(eHTMLTag_unknown!=theParentTag) {
02551 
02552       CElement* theParent=gElementTable->mElements[theParentTag];
02553 
02554       if(!theParent->CanContain(anElement,aContext)) {
02555         if(HasOptionalEndTag(theParentTag)) {
02556 
02557           if(ListContainsTag(theParent->mAutoClose,anElement->mTag)) {
02558             result=theParent->FindAutoCloseIndexForStartTag(anElement,aParentIndex-1,aContext);
02559           }
02560           else if((theParent->mTag==anElement->mTag) && (!theParent->mContainsGroups.mBits.mSelf)){
02561             result=aParentIndex;
02562           }
02563           else if(eHTMLTag_body!=theParent->mTag) {
02564             result=theParent->FindAutoCloseIndexForStartTag(anElement,aParentIndex-1,aContext);
02565           }
02566           else result=aParentIndex+1;
02567         }
02568         else result=kNotFound;
02569       } 
02570       else result=aParentIndex+1;
02571     }
02572   }
02573 
02574   return result;
02575 }
02576 
02577 /******************************************************************************
02578   Yes, I know it's inconvenient to find this methods here, but it's easier
02579   for the compiler -- and making it's life easier is my top priority.
02580  ******************************************************************************/
02581 PRBool CElement::CanBeClosedByEndTag(CElement* anElement,nsDTDContext* aContext) {
02582   PRBool result=PR_FALSE;
02583 
02584     //first, let's see if we can contain the given tag based on group info...
02585   if(anElement) {
02586     if(ListContainsTag(mAutoClose,anElement->mTag)) {
02587       return PR_TRUE;
02588     }
02589     else if((this==anElement) && (!mContainsGroups.mBits.mSelf)){
02590       return PR_TRUE;
02591     }
02592     else {
02593       eHTMLTags theTag=aContext->Last();
02594       CElement* theElement=gElementTable->mElements[theTag];
02595       if(HasOptionalEndTag(theTag)) {
02596         if(anElement->CanContain(theElement,aContext)){
02597           result=PR_TRUE;
02598         }
02599       }
02600     }
02601   }
02602   return result;
02603 }
02604 
02605 /******************************************************************************
02606   Yes, I know it's inconvenient to find this methods here, but it's easier
02607   for the compiler -- and making it's life easier is my top priority.
02608  ******************************************************************************/
02609 PRBool CElement::CanContain(CElement* anElement,nsDTDContext* aContext) {
02610   PRBool result=PR_FALSE;
02611 
02612     //first, let's see if we can contain the given tag based on group info...
02613   if(anElement) {
02614     if(!anElement->mProperties.mDeprecated) {
02615       if(anElement!=this) {
02616         if(ListContainsTag(mExcludeKids,anElement->mTag)) {
02617           return PR_FALSE;
02618         }
02619         else if(ContainsGroup(mContainsGroups,anElement->mGroup)) {
02620           result=PR_TRUE;
02621         }
02622         else if(ListContainsTag(mIncludeKids,anElement->mTag)) {
02623           return PR_TRUE;
02624         }
02625       }
02626       else result=mContainsGroups.mBits.mSelf;
02627     }    
02628 
02629       /***************************************************
02630         This is a (cheesy) exception table, that allows
02631         us to override containment for transitional 
02632         documents. A better implementation would be to
02633         create unique classes for each of the tags in 
02634         this table, and to override CanContain() there.
02635        ***************************************************/
02636     
02637     if((!result) && (aContext->mFlags.mTransitional)) {
02638       switch(mTag) {
02639         case eHTMLTag_address:
02640           if(eHTMLTag_p==anElement->mTag)
02641             result=PR_TRUE;
02642           break;
02643 
02644         case eHTMLTag_blockquote:
02645         case eHTMLTag_form:
02646         case eHTMLTag_iframe:
02647           result=ContainsGroup(CFlowElement::GetContainedGroups(),anElement->mGroup);            
02648           break;
02649 
02650         case eHTMLTag_button:
02651           if((eHTMLTag_iframe==anElement->mTag) || (eHTMLTag_isindex==anElement->mTag)) 
02652             result=PR_TRUE;
02653           break;
02654 
02655         default:
02656           break;
02657       }
02658     }
02659   }
02660   return result;
02661 }
02662 
02663 nsresult CElement::WillHandleStartToken(  CElement *anElement,
02664                                           nsIParserNode* aNode,
02665                                           eHTMLTags aTag,
02666                                           nsDTDContext* aContext,
02667                                           nsIHTMLContentSink* aSink) {
02668   nsresult result=NS_OK;
02669   return result;
02670 }
02671 
02672 nsresult CElement::HandleStartToken(  nsCParserNode* aNode,
02673                                       eHTMLTags aTag,
02674                                       nsDTDContext* aContext,
02675                                       nsIHTMLContentSink* aSink) {
02676 
02677   CElement* theElement=gElementTable->mElements[aTag];
02678 
02679   nsresult  result=WillHandleStartToken(theElement,aNode,aTag,aContext,aSink);
02680 
02681 #if 0
02682   CElement* theDelegate=theElement->GetDelegate();
02683   if(theDelegate) {
02684     result=theDelegate->HandleStartToken(aNode,aTag,aContext,aSink);
02685   }
02686   else 
02687 #endif
02688 
02689   {
02690     if(theElement) {
02691       if(CanContain(theElement,aContext)) {
02692     
02693         if(theElement->IsContainer()) {
02694           if(theElement->IsSinkContainer()) {
02695             result=theElement->OpenContainerInContext(aNode,aTag,aContext,aSink);
02696           }
02697           else {
02698             result=theElement->OpenContext(aNode,aTag,aContext,aSink);
02699           }
02700         }
02701         else {
02702           result=aSink->AddLeaf(*aNode); 
02703         }
02704       }
02705       else if(theElement->IsBlockCloser()){
02706 
02707         //Ok, so we have a start token that is misplaced. Before handing this off
02708         //to a default container (parent), let's check the autoclose condition.
02709         if(HasOptionalEndTag(mTag)) {
02710 
02711           //aha! We have a case where this tag is autoclosed by anElement.
02712           //Let's close this container, then try to open theElement.
02713           PRInt32 theCount=aContext->GetCount();
02714           PRInt32 theIndex=FindAutoCloseIndexForStartTag(theElement,theCount-2,aContext);
02715 
02716           //continue ripping code out here...
02717 
02718           if(kNotFound!=theIndex) {
02719             eHTMLTags theParentTag=eHTMLTag_unknown;
02720             CElement* theParent=0;
02721 
02722             while(NS_SUCCEEDED(result) && (theCount>theIndex)) {
02723 
02724               theParentTag=aContext->Last();
02725               theParent=gElementTable->mElements[theParentTag];
02726 
02727               nsCParserNode *theNode=aContext->PeekNode(); //this will get popped later...
02728               if(theParent->IsSinkContainer()) {
02729                 CloseContainerInContext(theNode,theParentTag,aContext,aSink);
02730               }
02731               else CloseContext(theNode,theParentTag,aContext,aSink);
02732               theCount--;
02733             }
02734 
02735             if(NS_SUCCEEDED(result)){
02736               theParentTag=aContext->Last();
02737               theParent=gElementTable->mElements[theParentTag];
02738               result=theParent->HandleStartToken(aNode,aTag,aContext,aSink);
02739             }
02740           }
02741           return result;
02742         }
02743         else {
02744           
02745           PRBool theElementCanOpen=PR_FALSE;
02746 
02747             //the logic here is simple:
02748             //  This operation can only succeed if the given tag is open, AND
02749             //  all the tags below it have optional end tags.
02750             //  If these conditions aren't met, we bail out, leaving the tag open.
02751 
02752           if(mTag!=aTag) {
02753             PRInt32 theLastPos=aContext->LastOf(aTag); //see if it's already open...
02754             if(-1!=theLastPos) {
02755               PRInt32 theCount=aContext->GetCount();
02756               result=HandleEndToken(aNode,aTag,aContext,aSink);
02757               theElementCanOpen=PRBool(aContext->GetCount()<theCount);
02758             }
02759           }
02760 
02761           if(theElementCanOpen) {
02762             if(NS_SUCCEEDED(result)){
02763               eHTMLTags theParentTag=aContext->Last();
02764               CElement* theParent=gElementTable->mElements[theParentTag];
02765               return theParent->HandleStartToken(aNode,aTag,aContext,aSink);
02766             }            
02767           }
02768         }
02769 
02770           //ok, here's our last recourse -- let's let the parent handle it.
02771         CElement* theContainer=GetDefaultContainerFor(theElement);
02772         if(theContainer) {
02773           result=theContainer->HandleMisplacedStartToken(aNode,aTag,aContext,aSink);
02774         }
02775       }
02776     }
02777   }
02778   return result;
02779 }
02780 
02781 
02782 nsresult CElement::HandleEndToken(nsCParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
02783   nsresult result=NS_OK;
02784 
02785   if(aContext->Last()==aTag) {
02786     CElement* theElement=gElementTable->mElements[aTag];
02787     if(theElement) {
02788       if(theElement->IsSinkContainer()) {
02789         result=CloseContainerInContext(aNode,aTag,aContext,aSink);
02790       }
02791       else result=CloseContext(aNode,aTag,aContext,aSink);
02792       return result;
02793     }
02794   }
02795 
02796   PRInt32   theCount=aContext->GetCount();
02797   PRInt32   theIndex=theCount-1;
02798 
02799   PRInt32 theCloseTarget=FindAutoCloseTargetForEndTag(aNode,aTag,aContext,aSink,theIndex);
02800 
02801   if(-1!=theCloseTarget) {
02802     while(theCloseTarget<theCount) {
02803       eHTMLTags theTag=aContext->Last();
02804       eHTMLTags theGrandParentTag=aContext->TagAt(theCount-2);
02805       CElement *theGrandParent=GetElement(theGrandParentTag);
02806       result=theGrandParent->HandleEndToken(aNode,theTag,aContext,aSink);
02807       theCount--;
02808     }
02809     //return result;
02810   }
02811   return result;
02812 }
02813 
02814 
02815 inline CElement* CElement::GetDelegate(void) {
02816   if(eHTMLTag_unknown!=mDelegate) {
02817     return gElementTable->mElements[mDelegate];
02818   }
02819   return 0;
02820 }
02821 
02822 inline CElement* CElement::GetDefaultContainerFor(CElement* anElement) {
02823   CElement* result=0;
02824 
02825   if(anElement) {
02826     if(anElement->mGroup.mBits.mBlock) {
02827       result=gElementTable->mElements[eHTMLTag_body];
02828     }
02829     else if(anElement->mGroup.mBits.mHeadContent) {
02830       result=gElementTable->mElements[eHTMLTag_head];
02831     }
02832     else if(anElement->mGroup.mBits.mHeadMisc) {
02833       result=gElementTable->mElements[eHTMLTag_head];
02834     }
02835   }
02836   return result;
02837 }
02838 
02839 
02840   //this tells us whether this tag is a block tag within the given parent
02841   //NOTE: aParentID is currently ignored, but shouldn't be.
02842 PRBool CElement::IsBlockElement(eHTMLTags aParentID) {
02843   CGroupMembers& theBlockGroup=CBlockElement::GetBlockGroupMembers();
02844   PRBool result=ContainsGroup(theBlockGroup,mGroup);
02845   return result;
02846 }
02847 
02848   //this tells us whether this tag is an inline tag within the given parent
02849   //NOTE: aParentID is currently ignored, but shouldn't be.
02850 PRBool CElement::IsInlineElement(eHTMLTags aParentID) {
02851   CGroupMembers& theInlineGroup=CInlineElement::GetContainedGroups();
02852   PRBool result=ContainsGroup(theInlineGroup,mGroup);
02853   return result;
02854 }
02855 
02856 
02857 #endif