Mozilla/mozilla/parser/htmlparser/src/COtherElements.h
bzbarsky%mit.edu ad59771509 Remove our broken attempt to support <plaintext> (which is very very
deprecated).  Bug 88987, r=jst, sr=dbaron


git-svn-id: svn://10.0.0.236/trunk@163474 18797224-902f-48f8-a5cc-f745e15eee43
2004-10-09 16:55:54 +00:00

2923 lines
104 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* rickg@netscape.com
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/************************************************************************
* MODULE NOTES:
* @update gess 04.08.2000
*
* - CElement::mAutoClose should only be set for tags whose end tag
* is optional.
*
*
************************************************************************/
#ifndef _COTHERELEMENTS_
#define _COTHERELEMENTS_
#include "nsDTDUtils.h"
/************************************************************************
This union is a bitfield which describes the group membership
************************************************************************/
struct CGroupBits {
PRUint32 mHead: 1;
PRUint32 mHeadMisc: 1; //script, style, meta, link, object
PRUint32 mHeadContent: 1; //title, base
PRUint32 mFontStyle : 1;
PRUint32 mPhrase: 1;
PRUint32 mSpecial: 1;
PRUint32 mFormControl: 1;
PRUint32 mHeading: 1;
PRUint32 mBlock: 1;
PRUint32 mFrame:1;
PRUint32 mList: 1;
PRUint32 mPreformatted: 1;
PRUint32 mTable: 1;
PRUint32 mSelf: 1;
PRUint32 mLeaf: 1;
PRUint32 mWhiteSpace: 1;
PRUint32 mComment: 1;
PRUint32 mTextContainer: 1;
PRUint32 mTopLevel: 1;
PRUint32 mDTDInternal: 1;
PRUint32 mFlowEntity: 1;
PRUint32 mBlockEntity: 1;
PRUint32 mInlineEntity: 1;
};
union CGroupMembers {
PRUint32 mAllBits;
CGroupBits mBits;
};
inline PRBool ContainsGroup(CGroupMembers& aGroupSet,CGroupMembers& aGroup) {
PRBool result=PR_FALSE;
if(aGroup.mAllBits) {
result=(aGroupSet.mAllBits & aGroup.mAllBits) ? PR_TRUE : PR_FALSE;
}
return result;
}
inline PRBool ListContainsTag(const eHTMLTags* aTagList,eHTMLTags aTag) {
if(aTagList) {
const eHTMLTags *theNextTag=aTagList;
while(eHTMLTag_unknown!=*theNextTag) {
if(aTag==*theNextTag) {
return PR_TRUE;
}
++theNextTag;
}
}
return PR_FALSE;
}
/**********************************************************
Begin with the baseclass for all elements...
**********************************************************/
class CElement {
public:
//break this struct out separately so that lame compilers don't gack.
struct CFlags {
PRUint32 mOmitEndTag:1;
PRUint32 mIsContainer:1;
PRUint32 mIsSinkContainer:1;
PRUint32 mDeprecated:1;
PRUint32 mOmitWS:1;
};
union {
PRUint32 mAllBits;
CFlags mProperties;
};
CElement(eHTMLTags aTag=eHTMLTag_unknown) {
mAllBits=0;
mTag=aTag;
mGroup.mAllBits=0;
mContainsGroups.mAllBits=0;
mAutoClose=mIncludeKids=mExcludeKids=0;
mDelegate=eHTMLTag_unknown;
}
CElement( eHTMLTags aTag,CGroupMembers& aGroup) {
mAllBits=0;
mTag=aTag;
mGroup=aGroup;
mContainsGroups.mAllBits=0;
mAutoClose=mIncludeKids=mExcludeKids=0;
mDelegate=eHTMLTag_unknown;
}
static CGroupMembers& GetEmptyGroup(void) {
static CGroupMembers theGroup={0};
return theGroup;
}
static void Initialize(CElement& anElement,eHTMLTags aTag){
anElement.mProperties.mIsContainer=0;
anElement.mProperties.mIsSinkContainer=0;
anElement.mTag=aTag;
anElement.mGroup.mAllBits=0;;
anElement.mContainsGroups.mAllBits=0;
}
static void InitializeLeaf(CElement& anElement,eHTMLTags aTag,CGroupMembers& aGroup,CGroupMembers& aContainsGroups) {
anElement.mProperties.mIsContainer=PR_FALSE;
anElement.mProperties.mIsSinkContainer=PR_FALSE;
anElement.mTag=aTag;
anElement.mGroup.mAllBits=aGroup.mAllBits;
anElement.mContainsGroups.mAllBits=aContainsGroups.mAllBits;
}
static void Initialize(CElement& anElement,eHTMLTags aTag,CGroupMembers& aGroup,CGroupMembers& aContainsGroups) {
anElement.mProperties.mIsContainer=PR_TRUE;
anElement.mProperties.mIsSinkContainer=PR_TRUE;
anElement.mTag=aTag;
anElement.mGroup.mAllBits=aGroup.mAllBits;
anElement.mContainsGroups.mAllBits=aContainsGroups.mAllBits;
}
inline CElement* GetDelegate(void);
inline CElement* GetDefaultContainerFor(CElement* anElement);
virtual PRBool CanContain(CElement* anElement,nsDTDContext* aContext);
virtual PRInt32 FindAutoCloseIndexForStartTag(CElement* anElement,PRInt32 aParentIndex,nsDTDContext* aContext);
virtual PRBool CanBeClosedByEndTag(CElement* anElement,nsDTDContext* aContext);
//This tells us whether this tag can potentially close other blocks.
//That DOES NOT mean that this tag is necessarily a block itself (condsider TBODY,TR,TD...)
virtual PRBool IsBlockCloser(void) {
PRBool result=IsBlockElement(eHTMLTag_body);
if(!result) {
if(IsInlineElement(eHTMLTag_body) ||
mGroup.mBits.mHead ||
mGroup.mBits.mHeadMisc ||
mGroup.mBits.mFormControl ||
mGroup.mBits.mFrame ||
mGroup.mBits.mLeaf ||
mGroup.mBits.mComment ||
mGroup.mBits.mTextContainer ||
mGroup.mBits.mWhiteSpace)
result=PR_FALSE;
else result=PR_TRUE;
}
return result;
}
//this tells us whether this tag is a block tag within the given parent
virtual PRBool IsBlockElement(eHTMLTags aParentID);
//this tells us whether this tag is an inline tag within the given parent
//NOTE: aParentID is currently ignored, but shouldn't be.
virtual PRBool IsInlineElement(eHTMLTags aParentID);
//this tells us whether the tag is a container as defined by HTML
//NOTE: aParentID is currently ignored, but shouldn't be.
virtual PRBool IsContainer(void) {return mProperties.mIsContainer; }
//this tells us whether the tag should be opened as a container in the sink (script doesn't, for example).
virtual PRBool IsSinkContainer(void) { return mProperties.mIsSinkContainer; }
virtual eHTMLTags GetSkipTarget(void) {return eHTMLTag_unknown;}
virtual nsresult WillHandleStartToken( CElement* anElement,
nsIParserNode* aNode,
eHTMLTags aTag,
nsDTDContext* aContext,
nsIHTMLContentSink* aSink);
virtual nsresult HandleStartToken( nsCParserNode* aNode,
eHTMLTags aTag,
nsDTDContext* aContext,
nsIHTMLContentSink* aSink);
virtual nsresult HandleEndToken(nsCParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink);
virtual nsresult HandleMisplacedStartToken(nsCParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
nsresult result=NS_OK;
return result;
}
virtual PRInt32 FindAutoCloseTargetForEndTag(nsCParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink, PRInt32& anIndex) {
PRInt32 result=-1;
if(mTag!=aTag) {
if(HasOptionalEndTag(mTag) && (0<anIndex)) {
eHTMLTags theGrandParentTag=aContext->TagAt(--anIndex);
CElement *theGrandParent=GetElement(theGrandParentTag);
if(theGrandParent) {
result=theGrandParent->FindAutoCloseTargetForEndTag(aNode,aTag,aContext,aSink,anIndex); //give the parent a chance...
}
}
}
else result=anIndex;
return result;
}
virtual nsresult HandleMisplacedEndToken(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
nsresult result=NS_OK;
return result;
}
nsresult AutoGenerateStructure(eHTMLTags *aTagList,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
nsresult result=NS_OK;
CStartToken theToken(*aTagList);
nsCParserNode theNode(&theToken, 0 /*stack token*/);
result=OpenContainer(&theNode,*aTagList,aContext,aSink);
if(eHTMLTag_unknown!=*(aTagList+1)) {
AutoGenerateStructure(++aTagList,aContext,aSink);
}
CEndToken theEndToken(*aTagList--);
nsCParserNode theEndNode(&theEndToken, 0 /*stack token*/);
result=CloseContainer(&theEndNode,*aTagList,aContext,aSink);
return result;
}
/**********************************************************
Call this for each element as it get's opened on the stack
**********************************************************/
virtual nsresult NotifyOpen(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
return NS_OK;
}
/**********************************************************
Call this for each element as it get's closed
**********************************************************/
virtual nsresult NotifyClose(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
return NS_OK;
}
/**********************************************************
this gets called after each tag is opened in the given context
**********************************************************/
virtual nsresult OpenContainer(nsIParserNode *aNode,eHTMLTags aTag,nsDTDContext *aContext,nsIHTMLContentSink *aSink) {
return aSink->OpenContainer(*aNode);
}
/**********************************************************
this gets called after each tag is opened in the given context
**********************************************************/
virtual nsresult OpenContext(nsCParserNode *aNode,eHTMLTags aTag,nsDTDContext *aContext,nsIHTMLContentSink *aSink) {
aContext->Push(aNode, 0, PR_FALSE);
CElement *theElement = (aTag == mTag) ? this : GetElement(aTag);
theElement->NotifyOpen(aNode, aTag, aContext,aSink);
return NS_OK;
}
/**********************************************************
this gets called after each tag is opened in the given context
**********************************************************/
virtual nsresult OpenContainerInContext(nsCParserNode *aNode,eHTMLTags aTag,nsDTDContext *aContext,nsIHTMLContentSink *aSink) {
OpenContext(aNode,aTag,aContext,aSink);
return OpenContainer(aNode,aTag,aContext,aSink);
}
/**********************************************************
this gets called to close a given tag in the sink
**********************************************************/
virtual nsresult CloseContainer(nsIParserNode *aNode,eHTMLTags aTag,nsDTDContext *aContext,nsIHTMLContentSink *aSink) {
return aSink->CloseContainer(aTag);
}
/**********************************************************
this gets called to close a tag in the given context
**********************************************************/
virtual nsresult CloseContext(nsCParserNode *aNode,eHTMLTags aTag,nsDTDContext *aContext,nsIHTMLContentSink *aSink) {
nsresult result=NS_OK;
nsEntryStack *theStack=0;
nsCParserNode *theNode=aContext->Pop(theStack);
CElement *theElement=(aTag==mTag) ? this : GetElement(aTag);
result=theElement->NotifyClose(theNode,aTag,aContext,aSink);
IF_FREE(aNode, aContext->mNodeAllocator);
return result;
}
/**********************************************************
this gets called to close a tag in the sink and in the context
**********************************************************/
virtual nsresult CloseContainerInContext(nsCParserNode *aNode,eHTMLTags aTag,nsDTDContext *aContext,nsIHTMLContentSink *aSink) {
nsresult result=NS_OK;
if(mTag!=aTag) {
CElement *theElement=GetElement(aTag);
return theElement->CloseContainerInContext(aNode,aTag,aContext,aSink);
}
result=CloseContainer(aNode,aTag,aContext,aSink);
CloseContext(aNode,aTag,aContext,aSink);
return result;
}
CElement* GetElement(eHTMLTags aTag);
eHTMLTags mTag;
eHTMLTags mDelegate;
CGroupMembers mGroup;
CGroupMembers mContainsGroups;
const eHTMLTags *mIncludeKids;
const eHTMLTags *mExcludeKids;
const eHTMLTags *mAutoClose; //other start tags that close this container
};
/**********************************************************
This defines the Special element group
**********************************************************/
class CLeafElement: public CElement {
public:
static CGroupMembers& GetGroup(void) {
static CGroupMembers theGroup={0};
theGroup.mBits.mLeaf=1;
return theGroup;
}
static CGroupMembers& GetContainedGroups(void) {
static CGroupMembers theGroups={0};
return theGroups;
}
static void Initialize(CElement& anElement,eHTMLTags aTag){
CElement::InitializeLeaf(anElement,aTag,GetGroup(),GetContainedGroups());
}
CLeafElement(eHTMLTags aTag) : CElement(aTag) {
mProperties.mIsContainer=0;
}
};
/**********************************************************
This defines elements that are deprecated
**********************************************************/
class CDeprecatedElement: public CElement {
public:
static void Initialize(CElement& anElement,eHTMLTags aTag){
CElement::Initialize(anElement,aTag);
anElement.mProperties.mDeprecated=1;
}
CDeprecatedElement(eHTMLTags aTag) : CElement(aTag) {
CDeprecatedElement::Initialize(*this,aTag);
}
};
/**********************************************************
This defines elements that are for use only by the DTD
**********************************************************/
class CInlineElement: public CElement {
public:
static CGroupMembers& GetGroup(void) {
static CGroupMembers theGroup={0};
theGroup.mBits.mInlineEntity=1;
return theGroup;
}
static CGroupMembers& GetContainedGroups(void) {
static CGroupMembers theGroup={0};
static PRBool initialized=PR_FALSE;
if(!initialized) {
initialized=PR_TRUE;
theGroup.mBits.mFormControl=1;
theGroup.mBits.mFontStyle =1;
theGroup.mBits.mPhrase=1;
theGroup.mBits.mSpecial=1;
theGroup.mBits.mList=0; //intentionally remove list from inline group
theGroup.mBits.mPreformatted=0;
theGroup.mBits.mSelf=1;
theGroup.mBits.mLeaf=1;
theGroup.mBits.mWhiteSpace=1;
theGroup.mBits.mComment=1;
theGroup.mBits.mInlineEntity=1;
}
return theGroup;
}
static void Initialize(CElement& anElement,eHTMLTags aTag){
CElement::Initialize(anElement,aTag,GetGroup(),GetContainedGroups());
}
CInlineElement(eHTMLTags aTag) : CElement(aTag) {
CInlineElement::Initialize(*this,aTag);
}
};
/**********************************************************
This defines the Block element group
**********************************************************/
class CBlockElement : public CElement {
public:
static CGroupMembers& GetGroup(void) {
static CGroupMembers theBlockGroup={0};
theBlockGroup.mBits.mBlock=1;
return theBlockGroup;
}
/**********************************************************
by default,members of the block group contain inline children
**********************************************************/
static CGroupMembers& GetContainedGroups(PRBool aCanContainSelf = PR_TRUE) {
static CGroupMembers theGroups=CInlineElement::GetContainedGroups();
theGroups.mBits.mSelf=aCanContainSelf;
return theGroups;
}
/**********************************************************
call this if you want a group that contains only block elements...
**********************************************************/
static CGroupMembers& GetBlockGroupMembers(void) {
static CGroupMembers theGroups={0};
theGroups.mBits.mBlock=1;
theGroups.mBits.mSelf=1;
return theGroups;
}
static void Initialize(CElement& anElement,eHTMLTags aTag){
CElement::Initialize(anElement,aTag,GetGroup(),GetContainedGroups());
}
CBlockElement(eHTMLTags aTag) : CElement(aTag) {
CBlockElement::Initialize(*this,aTag);
}
};
/************************************************************
This defines flowEntity elements that contain block+inline
************************************************************/
class CFlowElement: public CInlineElement {
public:
static CGroupMembers& GetGroup(void) {
static CGroupMembers theGroup={0};
theGroup.mBits.mFlowEntity=1;
return theGroup;
}
static CGroupMembers& GetContainedGroups(void) {
static CGroupMembers theGroup={0};
theGroup=CInlineElement::GetContainedGroups();
theGroup.mBits.mBlock=1;
theGroup.mBits.mBlockEntity=1;
return theGroup;
}
static void Initialize(CElement& anElement,eHTMLTags aTag){
CElement::Initialize(anElement,aTag,GetGroup(),GetContainedGroups());
}
CFlowElement(eHTMLTags aTag) : CInlineElement(aTag) {
CFlowElement::Initialize(*this,aTag);
}
};
/**********************************************************
This defines the Phrase element group
**********************************************************/
class CPhraseElement: public CElement {
public:
static CGroupMembers& GetGroup(void) {
static CGroupMembers thePhraseGroup={0};
thePhraseGroup.mBits.mPhrase=1;
return thePhraseGroup;
}
static CGroupMembers& GetContainedGroups(void) {
static CGroupMembers theGroups=CInlineElement::GetContainedGroups();
return theGroups;
}
static void Initialize(CElement& anElement,eHTMLTags aTag){
CElement::Initialize(anElement,aTag,GetGroup(),GetContainedGroups());
}
CPhraseElement(eHTMLTags aTag) : CElement(aTag) {
CPhraseElement::Initialize(*this,aTag);
}
};
/**********************************************************
This defines the formcontrol element group
**********************************************************/
class CFormControlElement: public CElement {
public:
static CGroupMembers& GetGroup(void) {
static CGroupMembers theGroup={0};
theGroup.mBits.mFormControl=1;
return theGroup;
}
static CGroupMembers& GetContainedGroups(void) {
static CGroupMembers theGroup={0};
theGroup.mBits.mFormControl=1;
theGroup.mBits.mLeaf=1;
theGroup.mBits.mWhiteSpace=1;
return theGroup;
}
static void Initialize(CElement& anElement,eHTMLTags aTag){
CElement::Initialize(anElement,aTag,GetGroup(),GetContainedGroups());
}
CFormControlElement(eHTMLTags aTag) : CElement(aTag) {
CFormControlElement::Initialize(*this,aTag);
}
};
/**********************************************************
This defines the form element itself
**********************************************************/
class CFormElement: public CBlockElement {
public:
static void Initialize(CElement& anElement,eHTMLTags aTag){
CElement::Initialize(anElement,aTag,CBlockElement::GetGroup(),CBlockElement::GetBlockGroupMembers());
}
CFormElement() : CBlockElement(eHTMLTag_form) {
CFormElement::Initialize(*this,eHTMLTag_form);
mContainsGroups.mBits.mSelf=0;
mContainsGroups.mBits.mFormControl=1;
}
virtual PRBool CanContain(CElement* anElement,nsDTDContext* aContext) {
PRBool result=CElement::CanContain(anElement,aContext);
if((!result) && (aContext->mFlags.mTransitional)) {
//If we're in transitional mode, then also allow inline elements...
CGroupMembers& theFlowGroup=CFlowElement::GetContainedGroups();
result=ContainsGroup(theFlowGroup,anElement->mGroup);
}
return result;
}
/**********************************************************
this gets called after each tag is opened in the given context
**********************************************************/
virtual nsresult OpenContainer(nsIParserNode *aNode,eHTMLTags aTag,nsDTDContext *aContext,nsIHTMLContentSink *aSink) {
nsresult result=aSink->OpenForm(*aNode);
return result;
}
};
/**********************************************************
This defines the fontstyle element group
**********************************************************/
class CFontStyleElement: public CElement {
public:
static CGroupMembers& GetGroup(void) {
static CGroupMembers theGroup={0};
theGroup.mBits.mFontStyle=1;
return theGroup;
}
static CGroupMembers& GetContainedGroups(void) {
static CGroupMembers theGroups=CInlineElement::GetContainedGroups();
return theGroups;
}
static void Initialize(CElement& anElement,eHTMLTags aTag){
CElement::Initialize(anElement,aTag,GetGroup(),GetContainedGroups());
}
CFontStyleElement(eHTMLTags aTag) : CElement(aTag) {
CFontStyleElement::Initialize(*this,aTag);
}
};
/**********************************************************
This defines the special-inline element group
**********************************************************/
class CSpecialElement : public CElement {
public:
static CGroupMembers& GetGroup(void) {
static CGroupMembers theGroup={0};
theGroup.mBits.mSpecial=1;
return theGroup;
}
static CGroupMembers& GetContainedGroups(void) {
static CGroupMembers theGroups=CInlineElement::GetContainedGroups();
return theGroups;
}
static void Initialize(CElement& anElement,eHTMLTags aTag){
CElement::Initialize(anElement,aTag,GetGroup(),GetContainedGroups());
}
CSpecialElement(eHTMLTags aTag) : CElement(aTag) {
CSpecialElement::Initialize(*this,aTag);
}
};
/**********************************************************
This defines the Table block itself, not it's children.
**********************************************************/
class CTableElement: public CElement {
public:
static CGroupMembers& GetGroup(void) {
static CGroupMembers theTableGroup={0};
theTableGroup.mBits.mTable=1;
return theTableGroup;
}
static CGroupMembers& GetContainedGroups(void) {
static CGroupMembers theGroups={0};
theGroups.mBits.mTable=1;
return theGroups;
}
static void Initialize(CElement& anElement,eHTMLTags aTag){
CElement::Initialize(anElement,aTag,GetGroup(),GetContainedGroups());
}
CTableElement(eHTMLTags aTag=eHTMLTag_table) : CElement(aTag) {
CElement::Initialize(*this,aTag,CBlockElement::GetGroup(),CTableElement::GetContainedGroups());
}
PRBool CanContain(CElement* anElement,nsDTDContext* aContext) {
PRBool result=PR_FALSE;
switch(anElement->mTag) {
case eHTMLTag_caption:
result=(aContext->mTableStates && aContext->mTableStates->CanOpenCaption());
break;
case eHTMLTag_colgroup:
result=(aContext->mTableStates && aContext->mTableStates->CanOpenCols());
break;
case eHTMLTag_thead: //nothing to do for these empty tags...
result=(aContext->mTableStates && aContext->mTableStates->CanOpenTHead());
break;
case eHTMLTag_tfoot:
result=(aContext->mTableStates && aContext->mTableStates->CanOpenTFoot());
break;
case eHTMLTag_tr:
case eHTMLTag_th:
result=(aContext->mTableStates && aContext->mTableStates->CanOpenTBody());
break;
default:
result=CElement::CanContain(anElement,aContext);
break;
}
return result;
}
/**********************************************************
Table needs to be notified so it can manage table states.
**********************************************************/
virtual nsresult NotifyOpen(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
aContext->mTableStates=new CTableState(aContext->mTableStates); //create and prepend a new state
return NS_OK;
}
/**********************************************************
Table needs to be notified so it can manage table states.
**********************************************************/
virtual nsresult NotifyClose(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
nsresult result=NS_OK;
if(aContext->mTableStates) {
if(!aContext->mTableStates->mHasTBody) {
//so let's open a tbody, a TR and a TD for good measure...
eHTMLTags theTags[]={eHTMLTag_tbody,eHTMLTag_tr,eHTMLTag_td,eHTMLTag_unknown};
AutoGenerateStructure(theTags,aContext,aSink);
}
//pop the current state and restore it's predecessor, if any...
CTableState *theState=aContext->mTableStates;
aContext->mTableStates=theState->mPrevious;
delete theState;
}
return result;
}
/**********************************************************
Table handles the opening of it's own children
**********************************************************/
virtual nsresult HandleStartToken(nsCParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
nsresult result=NS_OK;
switch(aTag) {
case eHTMLTag_caption:
if(aContext->mTableStates && aContext->mTableStates->CanOpenCaption()) {
result=OpenContainerInContext(aNode,aTag,aContext,aSink); //force the title onto the stack
}
break;
case eHTMLTag_col:
result=aSink->AddLeaf(*aNode);
break;
case eHTMLTag_colgroup:
if(aContext->mTableStates && aContext->mTableStates->CanOpenCols()) {
result=OpenContainerInContext(aNode,aTag,aContext,aSink); //force the title onto the stack
}
break;
case eHTMLTag_thead: //nothing to do for these empty tags...
if(aContext->mTableStates && aContext->mTableStates->CanOpenTHead()) {
aContext->mTableStates->mHasTHead=PR_TRUE;
result=OpenContainerInContext(aNode,aTag,aContext,aSink); //force the title onto the stack
}
break;
case eHTMLTag_tbody:
aContext->mTableStates->mHasTBody=PR_TRUE;
result=OpenContainerInContext(aNode,aTag,aContext,aSink); //force the title onto the stack
break;
case eHTMLTag_tfoot:
if(aContext->mTableStates && aContext->mTableStates->CanOpenTFoot()) {
aContext->mTableStates->mHasTFoot=PR_TRUE;
result=OpenContainerInContext(aNode,aTag,aContext,aSink); //force the title onto the stack
}
break;
case eHTMLTag_tr:
case eHTMLTag_th:
if(aContext->mTableStates) {
if(aContext->mTableStates->CanOpenTBody()) {
CToken* theToken=(CStartToken*)aContext->mTokenAllocator->CreateTokenOfType(eToken_start,eHTMLTag_tbody);
nsCParserNode* theNode=aContext->mNodeAllocator->CreateNode(theToken, 0);
result=HandleStartToken(theNode,eHTMLTag_tbody,aContext,aSink);
}
if(NS_SUCCEEDED(result)) {
CElement *theElement=GetElement(eHTMLTag_tbody);
if(theElement) {
result=theElement->HandleStartToken(aNode,aTag,aContext,aSink);
}
}
}
break;
default:
break;
}
return result;
}
/**********************************************************
Table handles the closing of it's own children
**********************************************************/
virtual nsresult HandleEndToken(nsCParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
nsresult result=NS_OK;
if(aContext->HasOpenContainer(aTag)) {
switch(aTag) {
case eHTMLTag_caption:
case eHTMLTag_col:
case eHTMLTag_colgroup:
case eHTMLTag_tr:
case eHTMLTag_thead:
case eHTMLTag_tfoot:
case eHTMLTag_tbody:
result=CloseContainerInContext(aNode,aTag,aContext,aSink); //force the title onto the stack
break;
default:
break;
} //switch
} //if
return result;
}
/**********************************************************
If you're here, then children below you have optional
end tags, can't deal with the given tag, and want you
to handle it.
**********************************************************/
virtual PRInt32 FindAutoCloseTargetForEndTag(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink, PRInt32& anIndex) {
// XXXldb This method is completely unused because the |aNode|
// parameter is declared as |nsIParserNode| rather than
// |nsCParserNode| so it doesn't override the member function of
// CElement.
NS_NOTREACHED("This isn't used. Should it be?");
PRInt32 result=kNotFound;
switch(aTag) {
case eHTMLTag_table:
case eHTMLTag_caption:
case eHTMLTag_col:
case eHTMLTag_colgroup:
case eHTMLTag_thead:
case eHTMLTag_tfoot:
case eHTMLTag_tbody:
case eHTMLTag_tr:
case eHTMLTag_td:
{
PRInt32 theTablePos=aContext->LastOf(eHTMLTag_table);
PRInt32 theTagPos=aContext->LastOf(aTag);
if((kNotFound!=theTagPos) && (theTablePos<=theTagPos)) {
result=theTagPos;
}
}
break;
default:
break;
} //switch
return result;
}
};
/**********************************************************
This defines the Table block itself, not it's children.
**********************************************************/
class CTableRowElement: public CElement {
public:
static void Initialize(CElement& anElement,eHTMLTags aTag){
CElement::Initialize(anElement,aTag,CTableElement::GetGroup(),CElement::GetEmptyGroup());
static eHTMLTags kTRKids[]={eHTMLTag_td,eHTMLTag_th,eHTMLTag_unknown};
anElement.mIncludeKids=kTRKids;
}
CTableRowElement(eHTMLTags aTag=eHTMLTag_tr) : CElement(aTag) {
CTableRowElement::Initialize(*this,aTag);
mContainsGroups.mBits.mSelf=0;
}
virtual nsresult HandleEndTokenForChild(CElement *aChild,nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
nsresult result=NS_OK;
return result;
}
};
/**********************************************************
This defines the List element group (ol,ul,dir,menu)
**********************************************************/
class CListElement: public CElement {
public:
static CGroupMembers& GetGroup(void) {
static CGroupMembers theListGroup={0};
theListGroup.mBits.mList=1;
return theListGroup;
}
static CGroupMembers& GetContainedGroups(void) {
static CGroupMembers theGroups=CInlineElement::GetContainedGroups();
return theGroups;
}
static void Initialize(CElement& anElement,eHTMLTags aTag){
CElement::Initialize(anElement,aTag,GetGroup(),GetContainedGroups());
}
CListElement(eHTMLTags aTag) : CElement(aTag) {
CListElement::Initialize(*this,aTag);
}
};
/**********************************************************
This defines the LI element...
An interesting problem here is that LI normally contains
Block+inline, unless it's inside a MENU or DIR, in which
case it contains only inline.
**********************************************************/
class CLIElement: public CElement {
public:
CLIElement(eHTMLTags aTag=eHTMLTag_li) : CElement(aTag) {
CFlowElement::Initialize(*this,aTag);
mGroup.mAllBits=0;
mGroup.mBits.mList=1;
}
};
/**********************************************************
This defines the counter element, and is for debug use.
Usage: <counter name="xxx" reset=n>
if you leave off the name key/value pair, we'll use the
name of the element instead.
**********************************************************/
class CCounterElement: public CInlineElement {
public:
CCounterElement(eHTMLTags aTag=eHTMLTag_counter) : CInlineElement(aTag) {
CInlineElement::Initialize(*this,aTag);
mProperties.mIsSinkContainer=PR_FALSE;
}
/**********************************************************
handles the opening of it's own children
**********************************************************/
virtual nsresult HandleStartToken( nsCParserNode* aNode,
eHTMLTags aTag,
nsDTDContext* aContext,
nsIHTMLContentSink* aSink) {
return CElement::HandleStartToken(aNode,aTag,aContext,aSink);
}
/**********************************************************
this gets called after each tag is opened in the given context
**********************************************************/
virtual nsresult OpenContext(nsCParserNode *aNode,eHTMLTags aTag,nsDTDContext *aContext,nsIHTMLContentSink *aSink) {
CElement::OpenContext(aNode,aTag,aContext,aSink);
nsresult result=NS_OK;
PRInt32 theCount=aContext->GetCount();
nsCParserNode *theNode = (nsCParserNode*)aNode;
#ifdef DEBUG
eHTMLTags theGrandParentTag=aContext->TagAt(theCount-2);
nsAutoString theNumber;
aContext->IncrementCounter(theGrandParentTag,*theNode,theNumber);
CTextToken theToken(theNumber);
nsCParserNode theNewNode(&theToken, 0 /*stack token*/);
*theNode = theNewNode;
#endif
result=aSink->AddLeaf(*theNode);
return result;
}
/**********************************************************
handles the opening of it's own children
**********************************************************/
virtual nsresult HandleEndToken(nsCParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
return CElement::HandleEndToken(aNode,aTag,aContext,aSink);
}
};
/**********************************************************
This defines the heading element group (h1..h6)
**********************************************************/
class CHeadingElement: public CElement {
public:
static CGroupMembers& GetGroup(void) {
static CGroupMembers theGroup={0};
theGroup.mBits.mHeading=1;
return theGroup;
}
static CGroupMembers& GetContainedGroups(void) {
static CGroupMembers theGroups=CInlineElement::GetContainedGroups();
return theGroups;
}
static void Initialize(CElement& anElement,eHTMLTags aTag){
CElement::Initialize(anElement,aTag,GetGroup(),GetContainedGroups());
}
CHeadingElement(eHTMLTags aTag) : CElement(aTag) {
CHeadingElement::Initialize(*this,aTag);
}
};
/**********************************************************
This defines the tags that relate to frames
**********************************************************/
class CFrameElement: public CElement {
public:
static CGroupMembers& GetGroup(void) {
static CGroupMembers theGroup={0};
theGroup.mBits.mFrame=1;
return theGroup;
}
static void Initialize(CElement& anElement,eHTMLTags aTag){
anElement.mProperties.mIsContainer=1;
anElement.mProperties.mIsSinkContainer=1;
anElement.mTag=aTag;
anElement.mGroup.mAllBits=0;
anElement.mGroup.mBits.mFrame=1;
anElement.mContainsGroups.mAllBits=0;
anElement.mContainsGroups.mBits.mFrame=1;
anElement.mContainsGroups.mBits.mSelf=1;
}
CFrameElement(eHTMLTags aTag) : CElement(aTag) {
CFrameElement::Initialize(*this,aTag);
}
};
/**********************************************************
This defines elements that are for use only by the DTD
**********************************************************/
class CDTDInternalElement: public CElement {
public:
static void Initialize(CElement& anElement,eHTMLTags aTag){
anElement.mProperties.mIsContainer=1;
anElement.mTag=aTag;
anElement.mContainsGroups.mAllBits=0;
anElement.mGroup.mBits.mDTDInternal=1;
}
CDTDInternalElement(eHTMLTags aTag) : CElement(aTag) {
CDTDInternalElement::Initialize(*this,aTag);
}
};
/**********************************************************
Here comes the head element
**********************************************************/
class CHeadElement: public CElement {
public:
static CGroupMembers& GetGroup(void) {
static CGroupMembers theHeadGroup={0};
theHeadGroup.mBits.mTopLevel=1;
return theHeadGroup;
}
static CGroupMembers& GetContentGroup(void) {
static CGroupMembers theGroup={0};
theGroup.mBits.mHeadContent=1;
return theGroup;
}
static CGroupMembers& GetMiscGroup(void) {
static CGroupMembers theGroup={0};
theGroup.mBits.mHeadMisc=1;
return theGroup;
}
static CGroupMembers& GetContainedGroups(void) {
static CGroupMembers theGroupsContainedByHead={0};
theGroupsContainedByHead.mBits.mHeadMisc=1;
theGroupsContainedByHead.mBits.mHeadContent=1;
return theGroupsContainedByHead;
}
static void Initialize(CElement& anElement,eHTMLTags aTag){
CElement::Initialize(anElement,aTag,GetGroup(),GetContainedGroups());
static eHTMLTags kHeadKids[]={eHTMLTag_isindex,eHTMLTag_unknown};
anElement.mIncludeKids=kHeadKids;
}
virtual nsresult OpenContext(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
// XXXldb This method is completely unused because the |aNode|
// parameter is declared as |nsIParserNode| rather than
// |nsCParserNode| so it doesn't override the member function of
// CElement.
NS_NOTREACHED("This isn't used. Should it be?");
NS_ASSERTION(aContext!=nsnull,"cannot make a decision without a context");
nsresult result=NS_OK;
if(aSink && aContext) {
if(aContext->mFlags.mHasOpenHead==PR_FALSE) {
result=aSink->OpenHead(*aNode);
aContext->mFlags.mHasOpenHead=PR_TRUE;
}
}
return result;
}
virtual nsresult CloseContext(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
// XXXldb This method is completely unused because the |aNode|
// parameter is declared as |nsIParserNode| rather than
// |nsCParserNode| so it doesn't override the member function of
// CElement.
NS_NOTREACHED("This isn't used. Should it be?");
NS_ASSERTION(aContext!=nsnull,"cannot make a decision without a context");
nsresult result=NS_OK;
if(aSink && aContext) {
if(aContext->mFlags.mHasOpenHead==PR_TRUE) {
result = aSink->CloseHead();
aContext->mFlags.mHasOpenHead=PR_FALSE;
}
}
return result;
}
CHeadElement(eHTMLTags aTag) : CElement(aTag) {
CHeadElement::Initialize(*this,aTag);
}
};
/**********************************************************
This class is for use with title, script, style
**********************************************************/
class CTextContainer : public CElement {
public:
static CGroupMembers& GetGroup(void) {
static CGroupMembers theGroup={0};
theGroup.mBits.mTextContainer=1;
return theGroup;
}
static CGroupMembers& GetContainedGroups(void) {
static CGroupMembers theContainedGroups={0};
theContainedGroups.mBits.mLeaf=1;
return theContainedGroups;
}
static void Initialize(CElement& anElement,eHTMLTags aTag){
CElement::Initialize(anElement,aTag,GetGroup(),GetContainedGroups());
}
CTextContainer(eHTMLTags aTag) : CElement(aTag) {
CTextContainer::Initialize(*this,aTag);
}
virtual ~CTextContainer() {
}
/**********************************************************
Call this for each element as it get's closed
**********************************************************/
virtual nsresult NotifyClose(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
nsresult result=NS_OK;
if(aNode) {
#if 0
CStartToken theToken(aTag);
nsCParserNode theNode(&theToken);
theNode.SetSkippedContent(mText);
result=aSink->AddLeaf(theNode);
#endif
nsCParserNode *theNode=(nsCParserNode*)aNode;
//theNode->SetSkippedContent(mText); XXX why do we need this?
result=aSink->AddLeaf(*theNode);
}
mText.Truncate(0);
return result;
}
/**********************************************************
Textcontainer handles the opening of it's own children
**********************************************************/
virtual nsresult HandleStartToken(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
// XXXldb This method is completely unused because the |aNode|
// parameter is declared as |nsIParserNode| rather than
// |nsCParserNode| so it doesn't override the member function of
// CElement.
NS_NOTREACHED("This isn't used. Should it be?");
nsresult result=NS_OK;
switch(aTag) {
case eHTMLTag_text:
case eHTMLTag_whitespace:
mText.Append(aNode->GetText());
break;
default:
break;
}
return result;
}
virtual nsresult HandleEndToken(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
// XXXldb This method is completely unused because the |aNode|
// parameter is declared as |nsIParserNode| rather than
// |nsCParserNode| so it doesn't override the member function of
// CElement.
NS_NOTREACHED("This isn't used. Should it be?");
nsresult result=NS_OK;
return result;
}
nsString mText;
};
/**********************************************************
This class is for the title element
**********************************************************/
class CTitleElement : public CTextContainer {
public:
static void Initialize(CElement& anElement,eHTMLTags aTag){
CTextContainer::Initialize(anElement,aTag);
}
CTitleElement() : CTextContainer(eHTMLTag_title) {
mGroup.mBits.mHeadMisc=1;
}
/**********************************************************
Call this for each element as it get's closed
**********************************************************/
virtual nsresult NotifyClose(nsCParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
// XXXldb This method is completely unused because the |aNode|
// parameter is declared as |nsCParserNode| rather than
// |nsIParserNode| so it doesn't override the member function of
// CTextContainer.
NS_NOTREACHED("This isn't used. Should it be?");
nsresult result=NS_OK;
CElement* theHead=GetElement(eHTMLTag_head);
if(theHead) {
result=theHead->OpenContext(aNode,aTag,aContext,aSink);
if(NS_SUCCEEDED(result)) {
result=aSink->SetTitle(mText);
mText.Truncate(0);
if(NS_SUCCEEDED(result)) {
result=theHead->CloseContext(aNode,aTag,aContext,aSink);
}
}
}
return result;
}
/**********************************************************
Title handles the opening of it's own children
**********************************************************/
virtual nsresult HandleStartToken(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
nsresult result=NS_OK;
switch(aTag) {
case eHTMLTag_text:
if(aNode && aNode->GetTokenType()==eToken_entity) {
nsAutoString tmp;
aNode->TranslateToUnicodeStr(tmp);
mText.Append(tmp);
break;
}
case eHTMLTag_whitespace:
mText.Append(aNode->GetText());
break;
default:
break;
}
return result;
}
};
/**********************************************************
This class is for the title element
**********************************************************/
class CTextAreaElement: public CTextContainer {
public:
CTextAreaElement() : CTextContainer(eHTMLTag_textarea) {
mGroup.mBits.mHeadMisc=1;
mGroup=CFormControlElement::GetGroup();
mProperties.mIsSinkContainer=0;
}
virtual nsresult HandleStartToken(nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
nsresult result=NS_OK;
switch(aTag) {
case eHTMLTag_text:
if(aNode && aNode->GetTokenType()==eToken_entity) {
nsAutoString tmp;
aNode->TranslateToUnicodeStr(tmp);
mText.Append(tmp);
break;
}
case eHTMLTag_whitespace:
case eHTMLTag_newline:
mText.Append(aNode->GetText());
break;
default:
break;
}
return result;
}
};
/**********************************************************
This class is for use with style
**********************************************************/
class CStyleElement: public CTextContainer {
public:
static void Initialize(CElement& anElement,eHTMLTags aTag){
CTextContainer::Initialize(anElement,aTag);
}
CStyleElement() : CTextContainer(eHTMLTag_style) {
mGroup.mBits.mHeadMisc=1;
}
/**********************************************************
Call this for each element as it get's closed
**********************************************************/
virtual nsresult NotifyClose(nsCParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
// XXXldb This method is completely unused because the |aNode|
// parameter is declared as |nsCParserNode| rather than
// |nsIParserNode| so it doesn't override the member function of
// CTextContainer.
NS_NOTREACHED("This isn't used. Should it be?");
nsresult result=NS_OK;
CElement* theHead=GetElement(eHTMLTag_head);
if(theHead) {
result=theHead->OpenContext(aNode,aTag,aContext,aSink);
if(NS_SUCCEEDED(result)) {
result=CTextContainer::NotifyClose(aNode,aTag,aContext,aSink);
mText.Truncate(0);
if(NS_SUCCEEDED(result)) {
result=theHead->CloseContext(aNode,aTag,aContext,aSink);
}
}
}
return result;
}
};
/**********************************************************
This class is for use with script
**********************************************************/
class CScriptElement: public CTextContainer {
public:
static void Initialize(CElement& anElement,eHTMLTags aTag){
CTextContainer::Initialize(anElement,aTag);
anElement.mProperties.mIsSinkContainer=PR_FALSE;
}
CScriptElement() : CTextContainer(eHTMLTag_script) {
mGroup.mBits.mHeadMisc=1;
mGroup.mBits.mInlineEntity=1;
mGroup.mBits.mSpecial=1;
mProperties.mIsSinkContainer=PR_FALSE;
}
/**********************************************************
this gets called after each tag is opened in the given context
**********************************************************/
virtual nsresult OpenContainerInContext(nsCParserNode *aNode,eHTMLTags aTag,nsDTDContext *aContext,nsIHTMLContentSink *aSink) {
OpenContext(aNode,aTag,aContext,aSink);
return NS_OK;
}
/**********************************************************
this gets called to close a tag in the given context
**********************************************************/
virtual nsresult CloseContext(nsIParserNode *aNode,eHTMLTags aTag,nsDTDContext *aContext,nsIHTMLContentSink *aSink) {
// XXXldb This method is completely unused because the |aNode|
// parameter is declared as |nsIParserNode| rather than
// |nsCParserNode| so it doesn't override the member function of
// CElement.
NS_NOTREACHED("This isn't used. Should it be?");
nsEntryStack* theStack=0;
nsIParserNode *theNode=aContext->Pop(theStack);
CElement *theElement=(aTag==mTag) ? this : GetElement(aTag);
theElement->NotifyClose(theNode,aTag,aContext,aSink);
return NS_OK;
}
/**********************************************************
Call this for each element as it get's closed
**********************************************************/
virtual nsresult NotifyClose(nsCParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
// XXXldb This method is completely unused because the |aNode|
// parameter is declared as |nsCParserNode| rather than
// |nsIParserNode| so it doesn't override the member function of
// CTextContainer.
NS_NOTREACHED("This isn't used. Should it be?");
nsresult result=NS_OK;
if(aContext->HasOpenContainer(eHTMLTag_body)) {
//add the script to the body
result=CTextContainer::NotifyClose(aNode,aTag,aContext,aSink);
}
else {
//add it to the head...
CElement* theHead=GetElement(eHTMLTag_head);
if(theHead) {
result=theHead->OpenContext(aNode,aTag,aContext,aSink);
if(NS_SUCCEEDED(result)) {
result=CTextContainer::NotifyClose(aNode,aTag,aContext,aSink);
if(NS_SUCCEEDED(result)) {
result=theHead->CloseContext(aNode,aTag,aContext,aSink);
}
}
}
}
mText.Truncate(0);
return result;
}
};
/**********************************************************
This defines the preformatted element group, (PRE).
**********************************************************/
class CPreformattedElement: public CBlockElement {
public:
static void Initialize(CElement& anElement,eHTMLTags aTag){
CBlockElement::Initialize(anElement,aTag);
}
CPreformattedElement(eHTMLTags aTag) : CBlockElement(aTag) {
mGroup=GetGroup();
mContainsGroups=GetContainedGroups();
mProperties.mIsContainer=1;
}
/**********************************************************
Pre handles the opening of it's own children
**********************************************************/
virtual nsresult HandleStartToken(nsCParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
nsresult result=CElement::HandleStartToken(aNode,aTag,aContext,aSink);
return result;
}
/**********************************************************
Pre handles the closing of it's own children
**********************************************************/
virtual nsresult HandleEndToken(nsCParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
nsresult result=CElement::HandleEndToken(aNode,aTag,aContext,aSink);
return result;
}
};
/**********************************************************
This is used for both applet and object elements
**********************************************************/
class CAppletElement: public CSpecialElement {
public:
static CGroupMembers& GetGroup(void) {
static CGroupMembers theGroup={0};
theGroup.mBits.mSpecial=1;
theGroup.mBits.mBlock=1;
return theGroup;
}
static CGroupMembers& GetContainedGroups(void) {
return CFlowElement::GetContainedGroups();
}
static void Initialize(CElement& anElement,eHTMLTags aTag){
CElement::Initialize(anElement,aTag,GetGroup(),GetContainedGroups());
static eHTMLTags kSpecialKids[]={eHTMLTag_param,eHTMLTag_unknown};
anElement.mIncludeKids=kSpecialKids;
anElement.mProperties.mIsContainer=1;
}
CAppletElement(eHTMLTags aTag) : CSpecialElement(aTag) {
Initialize(*this,aTag);
}
/**********************************************************
handles the opening of it's own children
**********************************************************/
virtual nsresult HandleStartToken(nsCParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
nsresult result=NS_OK;
nsIParserNode *theNode=aContext->PeekNode();
if(theNode) {
PRBool theContentsHaveArrived=theNode->GetGenericState();
switch(aTag) {
case eHTMLTag_param:
if(!theContentsHaveArrived) {
result=CElement::HandleStartToken(aNode,aTag,aContext,aSink);
}
break;
case eHTMLTag_newline:
case eHTMLTag_whitespace:
result=CElement::HandleStartToken(aNode,aTag,aContext,aSink);
break;
default:
theNode->SetGenericState(PR_TRUE);
result=CElement::HandleStartToken(aNode,aTag,aContext,aSink);
break;
} //switch
}
return result;
}
};
/**********************************************************
This defines the fieldset element...
**********************************************************/
class CFieldsetElement: public CBlockElement {
public:
static CGroupMembers& GetGroup(void) {
static CGroupMembers theGroup={0};
theGroup.mBits.mBlock=1;
return theGroup;
}
static CGroupMembers& GetContainedGroups(void) {
return CFlowElement::GetContainedGroups();
}
static void Initialize(CElement& anElement,eHTMLTags aTag){
CElement::Initialize(anElement,aTag,GetGroup(),GetContainedGroups());
}
CFieldsetElement() : CBlockElement(eHTMLTag_fieldset) {
mGroup=GetGroup();
mContainsGroups=GetContainedGroups();
mProperties.mIsContainer=1;
}
/**********************************************************
fieldset handles the opening of it's own children
**********************************************************/
virtual nsresult HandleStartToken(nsCParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
nsresult result=NS_OK;
nsIParserNode *theNode=aContext->PeekNode();
if(theNode) {
PRBool theLegendExists=theNode->GetGenericState();
switch(aTag) {
case eHTMLTag_legend:
if(!theLegendExists) {
theNode->SetGenericState(PR_TRUE);
result=OpenContainerInContext(aNode,aTag,aContext,aSink); //force the title onto the stack
}
break;
default:
if(theLegendExists) {
result=CElement::HandleStartToken(aNode,aTag,aContext,aSink); //force the title onto the stack
}
break;
} //switch
}
return result;
}
};
/**********************************************************
This is for FRAMESET, etc.
**********************************************************/
class CTopLevelElement: public CElement {
public:
static CGroupMembers& GetGroup(void) {
static CGroupMembers theGroup={0};
theGroup.mBits.mTopLevel=1;
return theGroup;
}
static CGroupMembers& GetContainedGroups(void) {
static CGroupMembers theGroup=CFlowElement::GetContainedGroups();
return theGroup;
}
static void Initialize(CElement& anElement,eHTMLTags aTag){
CElement::Initialize(anElement,aTag,GetGroup(),GetContainedGroups());
}
CTopLevelElement(eHTMLTags aTag) : CElement(aTag) {
CTopLevelElement::Initialize(*this,aTag);
}
/**********************************************************
Toplevel handles the opening of it's own children
**********************************************************/
virtual nsresult HandleStartToken( nsCParserNode* aNode,
eHTMLTags aTag,
nsDTDContext* aContext,
nsIHTMLContentSink* aSink) {
nsresult result=NS_OK;
switch(aTag) {
case eHTMLTag_unknown:
default:
result=CElement::HandleStartToken(aNode,aTag,aContext,aSink);
break;
}//switch
return result;
}
/**********************************************************
TopLevel handles the opening of it's own children
**********************************************************/
virtual nsresult HandleEndToken(nsCParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
nsresult result=NS_OK;
switch(aTag) {
case eHTMLTag_html:
if(aContext->HasOpenContainer(aTag)) {
result=aSink->CloseHTML();
CloseContext(aNode,aTag,aContext,aSink);
}
break;
case eHTMLTag_body:
if(aContext->HasOpenContainer(aTag)) {
result=aSink->CloseBody();
CloseContext(aNode,aTag,aContext,aSink);
}
break;
case eHTMLTag_frameset:
if(aContext->HasOpenContainer(aTag)) {
result=aSink->OpenFrameset(*aNode);
CloseContext(aNode,aTag,aContext,aSink);
}
break;
default:
result=CElement::HandleEndToken(aNode,aTag,aContext,aSink);
break;
}//switch
return result;
}
};
/**********************************************************
This is for HTML only...
**********************************************************/
class CHTMLElement: public CTopLevelElement{
public:
static CGroupMembers& GetGroup(void) {
static CGroupMembers theBlockGroup={0};
theBlockGroup.mBits.mTopLevel=1;
return theBlockGroup;
}
static CGroupMembers& GetContainedGroups(void) {
static CGroupMembers theGroups={0};
theGroups.mBits.mTopLevel=1;
return theGroups;
}
CHTMLElement(eHTMLTags aTag) : CTopLevelElement(aTag) {
CElement::Initialize(*this,aTag,CHTMLElement::GetGroup(),CHTMLElement::GetContainedGroups());
}
/**********************************************************
HTML handles the opening of it's own children
**********************************************************/
nsresult HandleDoctypeDecl( nsIParserNode* aNode,
eHTMLTags aTag,
nsDTDContext* aContext,
nsIHTMLContentSink* aSink) {
nsCParserNode *theNode=(nsCParserNode*)aNode;
nsresult result=NS_OK;
if(theNode) {
nsAutoString theStr(theNode->mToken->GetStringValue());
PRInt32 theLen=theStr.Length();
//PRInt32 thePos=theStr.RFindChar(kGreaterThan);
theStr.Truncate(theLen-1);
theStr.Cut(0,2);
result = aSink->AddDocTypeDecl(*aNode);
}
return result;
}
/**********************************************************
HTML handles the opening of it's own children
**********************************************************/
virtual nsresult HandleStartToken( nsCParserNode* aNode,
eHTMLTags aTag,
nsDTDContext* aContext,
nsIHTMLContentSink* aSink) {
nsresult result=NS_OK;
switch(aTag) {
case eHTMLTag_doctypeDecl:
result=HandleDoctypeDecl(aNode,aTag,aContext,aSink);
break;
case eHTMLTag_frameset:
result=aSink->OpenFrameset(*aNode);
result=OpenContext(aNode,aTag,aContext,aSink);
aContext->mFlags.mHadFrameset=PR_TRUE;
break;
case eHTMLTag_base: //nothing to do for these empty tags...
case eHTMLTag_isindex:
case eHTMLTag_link:
case eHTMLTag_meta:
{
CElement* theHead=GetElement(eHTMLTag_head);
if(theHead) {
result=theHead->OpenContext(aNode,aTag,aContext,aSink);
if(NS_SUCCEEDED(result)) {
result=aSink->AddLeaf(*aNode);
if(NS_SUCCEEDED(result)) {
result=theHead->CloseContext(aNode,aTag,aContext,aSink);
}
}
}
}
break;
case eHTMLTag_object:
{
CElement* theHead=GetElement(eHTMLTag_head);
if(theHead) {
result=theHead->OpenContext(aNode,aTag,aContext,aSink);
if(NS_SUCCEEDED(result)) {
result=OpenContainerInContext(aNode,aTag,aContext,aSink);
}
}
}
break;
case eHTMLTag_script:
case eHTMLTag_style:
case eHTMLTag_title:
result=OpenContext(aNode,aTag,aContext,aSink); //force the title onto the context stack
break;
case eHTMLTag_newline:
case eHTMLTag_whitespace:
case eHTMLTag_comment:
break;
default:
CElement* theBody=GetElement(eHTMLTag_body);
if(theBody) {
CElement *theChildElement=GetElement(aTag);
if(theBody->CanContain(theChildElement,aContext)) {
//let's auto open the body
CToken* theToken=(CStartToken*)aContext->mTokenAllocator->CreateTokenOfType(eToken_start,eHTMLTag_body);
nsCParserNode* theNode=aContext->mNodeAllocator->CreateNode(theToken, 0);
result=theBody->HandleStartToken(theNode,eHTMLTag_body,aContext,aSink);
if(NS_SUCCEEDED(result)) {
if(eHTMLTag_body==aContext->Last()) {
result=theBody->HandleStartToken(aNode,aTag,aContext,aSink);
}
}
}
}
//for now, let's drop other elements onto the floor.
break;
}//switch
return result;
}
/**********************************************************
HTML handles the closing of it's own children
**********************************************************/
virtual nsresult HandleEndToken(nsCParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
nsresult result=NS_OK;
switch(aTag) {
case eHTMLTag_body:
aSink->CloseBody();
result=CloseContext(aNode,aTag,aContext,aSink);
break;
case eHTMLTag_frameset:
aSink->CloseFrameset();
result=CloseContext(aNode,aTag,aContext,aSink);
break;
case eHTMLTag_object:
result=CloseContainerInContext(aNode,aTag,aContext,aSink);
aSink->CloseHead();
break;
case eHTMLTag_script:
case eHTMLTag_style:
case eHTMLTag_title:
result=CloseContext(aNode,aTag,aContext,aSink); //close the title
break;
case eHTMLTag_unknown:
default:
result=CTopLevelElement::HandleEndToken(aNode,aTag,aContext,aSink);
}
return result;
}
};
/**********************************************************
This is for the body element...
**********************************************************/
static const eHTMLTags gBodyKids[] = {eHTMLTag_button, eHTMLTag_del, eHTMLTag_ins, eHTMLTag_map,eHTMLTag_script, eHTMLTag_unknown};
static const eHTMLTags gBodyExcludeKids[] = {eHTMLTag_applet, eHTMLTag_button, eHTMLTag_iframe, eHTMLTag_object, eHTMLTag_unknown};
class CBodyElement: public CElement {
public:
static CGroupMembers& GetGroup(void) {
static CGroupMembers theGroup={0};
theGroup.mBits.mTopLevel=1;
return theGroup;
}
CBodyElement(eHTMLTags aTag=eHTMLTag_body) : CElement(aTag) {
CGroupMembers theGroups=CBlockElement::GetBlockGroupMembers();
CElement::Initialize(*this,aTag,CBodyElement::GetGroup(),theGroups);
mIncludeKids=gBodyKids;
mExcludeKids=gBodyExcludeKids;
}
virtual PRBool CanContain(CElement* anElement,nsDTDContext* aContext) {
PRBool result=CElement::CanContain(anElement,aContext);
if((!result) && (aContext->mFlags.mTransitional)) {
//let's try so additions that are specific to the body tag,
//and only work in transitional mode...
CGroupMembers& theFlowGroup=CFlowElement::GetContainedGroups();
result=ContainsGroup(theFlowGroup,anElement->mGroup);
}
return result;
}
//this gets called after each tag is opened in the given context
virtual nsresult OpenContainer(nsCParserNode *aNode,eHTMLTags aTag,nsDTDContext *aContext,nsIHTMLContentSink *aSink) {
// XXXldb This method is completely unused because the |aNode|
// parameter is declared as |nsCParserNode| rather than
// |nsIParserNode| so it doesn't override the member function of
// CElement.
NS_NOTREACHED("This isn't used. Should it be?");
nsresult result=NS_OK;
if(mTag==aTag) {
// Close the head before opening a body.
CElement* theHead=GetElement(eHTMLTag_head);
result=theHead->CloseContext(aNode,aTag,aContext,aSink);
if(NS_SUCCEEDED(result)) {
result=aSink->OpenBody(*aNode);
}
}
else result=CElement::OpenContainer(aNode,aTag,aContext,aSink);
return result;
}
/**********************************************************
this gets called after each tag is opened in the given context
**********************************************************/
virtual nsresult OpenContainerInContext(nsCParserNode *aNode,eHTMLTags aTag,nsDTDContext *aContext,nsIHTMLContentSink *aSink) {
NS_ASSERTION(aContext!=nsnull,"need a valid context");
nsresult result=NS_OK;
// Since BODY is optional, we might come across more than one BODY!.
// That is, one that's auto opened and one that came from the document itself.
// If that's the case then make sure that we don't open up multiple contexts, however,
// don't forget to inform the sink because it needs to account for the BODY attributes.
if(aContext) {
if(!aContext->mFlags.mHadBody) {
result=OpenContext(aNode,aTag,aContext,aSink);
aContext->mFlags.mHadBody=PR_TRUE;
}
}
return (NS_SUCCEEDED(result))? OpenContainer(aNode,aTag,aContext,aSink):result;
}
/**********************************************************
Body handles the opening of it's own children
**********************************************************/
virtual nsresult HandleStartToken( nsCParserNode* aNode,
eHTMLTags aTag,
nsDTDContext* aContext,
nsIHTMLContentSink* aSink) {
//for now, let's drop other elements onto the floor.
nsresult result=CElement::HandleStartToken(aNode,aTag,aContext,aSink);
if(NS_SUCCEEDED(result)) {
if(aNode) {
nsCParserNode* theNode=(nsCParserNode*)aNode;
eHTMLTokenTypes theType=eHTMLTokenTypes(theNode->GetTokenType());
if(theType==eToken_start) {
CStartToken *theToken=(CStartToken*)theNode->mToken;
if(theToken && theToken->IsEmpty() && (aTag==aContext->Last())){
result=CElement::HandleEndToken(aNode,aTag,aContext,aSink);
}
}
}
}
return result;
}
/**********************************************************
Body doesnt really need to handle it's own kids, but it's
a really convenient break point for debugging purposes.
**********************************************************/
virtual nsresult HandleEndToken(nsCParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
nsresult result=NS_OK;
switch(aTag) {
case eHTMLTag_script:
result=CloseContext(aNode,aTag,aContext,aSink);
break;
default:
result=CElement::HandleEndToken(aNode,aTag,aContext,aSink);
}
return result;
}
/**********************************************************
Body is the default place where forwarding stops.
**********************************************************/
virtual nsresult HandleEndTokenForChild(CElement *aChild,nsIParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
nsresult result=NS_OK;
return result;
}
protected:
};
/************************************************************************
This describes each group that each HTML element belongs to
************************************************************************/
class CElementTable {
public:
enum {eGroupCount=4};
CElementTable() :
mBodyElement(eHTMLTag_body),
mFramesetElement(eHTMLTag_frameset),
mHTMLElement(eHTMLTag_html),
mScriptElement(),
mStyleElement(),
mTitleElement(),
mTextAreaElement(),
mPreElement(eHTMLTag_pre),
mLIElement(eHTMLTag_li),
mAppletElement(eHTMLTag_applet),
mObjectElement(eHTMLTag_object),
mFieldsetElement(),
mCounterElement(),
mFormElement(),
mHeadElement(eHTMLTag_head)
{
memset(mElements,0,sizeof(mElements));
InitializeElements();
//DebugDumpBlockElements("test");
//DebugDumpInlineElements("test");
//DebugDumpContainment("all elements");
}
//call this to get a ptr to an element prototype...
CElement* GetElement(eHTMLTags aTagID) {
if(aTagID>eHTMLTag_unknown) {
if(aTagID<eHTMLTag_userdefined) {
return mElements[aTagID];
}
}
return 0;
}
void InitializeElements();
#ifdef DEBUG
void DebugDumpGroups(CElement* aParent);
void DebugDumpContainment(const char* aTitle);
void DebugDumpContainment(CElement* aParent);
void DebugDumpInlineElements(const char* aTitle);
void DebugDumpBlockElements(const char* aTitle);
#endif
CElement* mElements[150]; //add one here for special handling of a given element
CElement mDfltElements[150];
CBodyElement mBodyElement;
CFrameElement mFramesetElement;
CHTMLElement mHTMLElement;
CScriptElement mScriptElement;
CStyleElement mStyleElement;
CTitleElement mTitleElement;
CTextAreaElement mTextAreaElement;
CPreformattedElement mPreElement;
CTableElement mTableElement;
CLIElement mLIElement;
CAppletElement mAppletElement;
CAppletElement mObjectElement;
CFieldsetElement mFieldsetElement;
CCounterElement mCounterElement;
CFormElement mFormElement;
CHeadElement mHeadElement;
};
static CElementTable *gElementTable = 0;
static const eHTMLTags kDLKids[]={eHTMLTag_dd,eHTMLTag_dt,eHTMLTag_unknown};
static const eHTMLTags kAutoCloseDD[]={eHTMLTag_dd,eHTMLTag_dt,eHTMLTag_dl,eHTMLTag_unknown};
static const eHTMLTags kButtonExcludeKids[]={ eHTMLTag_a,eHTMLTag_button,eHTMLTag_select,eHTMLTag_textarea,
eHTMLTag_input,eHTMLTag_iframe,eHTMLTag_form,eHTMLTag_isindex,
eHTMLTag_fieldset,eHTMLTag_unknown};
static const eHTMLTags kColgroupKids[]={eHTMLTag_col,eHTMLTag_unknown};
static const eHTMLTags kDirKids[]={eHTMLTag_li,eHTMLTag_unknown};
static const eHTMLTags kOptionGroupKids[]={eHTMLTag_option,eHTMLTag_unknown};
static const eHTMLTags kFieldsetKids[]={eHTMLTag_legend,eHTMLTag_unknown};
static const eHTMLTags kFormKids[]={eHTMLTag_script,eHTMLTag_unknown};
static const eHTMLTags kLIExcludeKids[]={eHTMLTag_dir,eHTMLTag_menu,eHTMLTag_unknown};
static const eHTMLTags kMapKids[]={eHTMLTag_area,eHTMLTag_unknown};
static const eHTMLTags kPreExcludeKids[]={eHTMLTag_image,eHTMLTag_object,eHTMLTag_applet,
eHTMLTag_big,eHTMLTag_small,eHTMLTag_sub,eHTMLTag_sup,
eHTMLTag_font,eHTMLTag_basefont,eHTMLTag_unknown};
static const eHTMLTags kSelectKids[]={eHTMLTag_optgroup,eHTMLTag_option,eHTMLTag_unknown};
static const eHTMLTags kBlockQuoteKids[]={eHTMLTag_script,eHTMLTag_unknown};
static const eHTMLTags kFramesetKids[]={eHTMLTag_noframes,eHTMLTag_unknown};
static const eHTMLTags kObjectKids[]={eHTMLTag_param,eHTMLTag_unknown};
static const eHTMLTags kTBodyKids[]={eHTMLTag_tr,eHTMLTag_unknown};
static const eHTMLTags kUnknownKids[]={eHTMLTag_html,eHTMLTag_unknown};
inline CElement* CElement::GetElement(eHTMLTags aTag) {
return gElementTable->mElements[aTag];
}
/***********************************************************************************
This method is pretty interesting, because it's where the elements all get
initialized for this elementtable.
***********************************************************************************/
void CElementTable::InitializeElements() {
int max=sizeof(mElements)/sizeof(mElements[0]);
int index=0;
for(index=0;index<max;++index){
mElements[index]=&mDfltElements[index];
}
CSpecialElement::Initialize( mDfltElements[eHTMLTag_a], eHTMLTag_a);
mDfltElements[eHTMLTag_a].mContainsGroups.mBits.mSelf=0;
CPhraseElement::Initialize( mDfltElements[eHTMLTag_abbr], eHTMLTag_abbr);
CPhraseElement::Initialize( mDfltElements[eHTMLTag_acronym], eHTMLTag_acronym);
CBlockElement::Initialize( mDfltElements[eHTMLTag_address], eHTMLTag_address);
CElement::Initialize( mDfltElements[eHTMLTag_applet], eHTMLTag_applet,CSpecialElement::GetGroup(), CFlowElement::GetContainedGroups());
CElement::Initialize( mDfltElements[eHTMLTag_area], eHTMLTag_area);
mDfltElements[eHTMLTag_area].mContainsGroups.mBits.mSelf=0;
CFontStyleElement::Initialize( mDfltElements[eHTMLTag_b], eHTMLTag_b);
CElement::InitializeLeaf( mDfltElements[eHTMLTag_base], eHTMLTag_base, CHeadElement::GetMiscGroup(), CLeafElement::GetContainedGroups());
CElement::InitializeLeaf( mDfltElements[eHTMLTag_basefont], eHTMLTag_basefont, CSpecialElement::GetGroup(), CLeafElement::GetContainedGroups());
CSpecialElement::Initialize( mDfltElements[eHTMLTag_bdo], eHTMLTag_bdo);
CFontStyleElement::Initialize( mDfltElements[eHTMLTag_big], eHTMLTag_big);
CDeprecatedElement::Initialize( mDfltElements[eHTMLTag_bgsound], eHTMLTag_bgsound);
CElement::Initialize( mDfltElements[eHTMLTag_blockquote], eHTMLTag_blockquote, CBlockElement::GetGroup(), CBlockElement::GetBlockGroupMembers());
mDfltElements[eHTMLTag_blockquote].mIncludeKids=kBlockQuoteKids;
//CBodyElement::Initialize( mDfltElements[eHTMLTag_body], eHTMLTag_body);
CElement::InitializeLeaf( mDfltElements[eHTMLTag_br], eHTMLTag_br, CSpecialElement::GetGroup(), CLeafElement::GetContainedGroups());
CElement::Initialize( mDfltElements[eHTMLTag_button], eHTMLTag_button, CFormControlElement::GetGroup(), CFlowElement::GetContainedGroups());
mDfltElements[eHTMLTag_button].mGroup.mBits.mBlock=1; //make this a member of the block group.
mDfltElements[eHTMLTag_button].mExcludeKids=kButtonExcludeKids;
CElement::Initialize( mDfltElements[eHTMLTag_caption], eHTMLTag_caption, CTableElement::GetGroup(), CSpecialElement::GetContainedGroups());
mDfltElements[eHTMLTag_tr].mContainsGroups.mBits.mSelf=0;
CElement::Initialize( mDfltElements[eHTMLTag_center], eHTMLTag_center, CBlockElement::GetGroup(), CFlowElement::GetContainedGroups());
CPhraseElement::Initialize( mDfltElements[eHTMLTag_cite], eHTMLTag_cite);
CPhraseElement::Initialize( mDfltElements[eHTMLTag_code], eHTMLTag_code);
CElement::Initialize( mDfltElements[eHTMLTag_col], eHTMLTag_col, CTableElement::GetGroup(), CLeafElement::GetContainedGroups());
mDfltElements[eHTMLTag_col].mProperties.mIsContainer=0;
CTableElement::Initialize( mDfltElements[eHTMLTag_colgroup], eHTMLTag_colgroup);
mDfltElements[eHTMLTag_colgroup].mContainsGroups.mAllBits=0;
mDfltElements[eHTMLTag_colgroup].mIncludeKids=kColgroupKids;
CElement::Initialize( mDfltElements[eHTMLTag_counter], eHTMLTag_counter);
CElement::Initialize( mDfltElements[eHTMLTag_dd], eHTMLTag_dd, CElement::GetEmptyGroup(), CFlowElement::GetContainedGroups());
mDfltElements[eHTMLTag_dd].mAutoClose=kAutoCloseDD;
mDfltElements[eHTMLTag_dd].mContainsGroups.mBits.mSelf=0;
CElement::Initialize( mDfltElements[eHTMLTag_del], eHTMLTag_del, CPhraseElement::GetGroup(), CFlowElement::GetContainedGroups());
mDfltElements[eHTMLTag_del].mGroup.mBits.mBlock=1; //make this a member of the block group.
CElement::Initialize( mDfltElements[eHTMLTag_dfn], eHTMLTag_dfn, CPhraseElement::GetGroup(), CInlineElement::GetContainedGroups());
CBlockElement::Initialize( mDfltElements[eHTMLTag_dir], eHTMLTag_dir);
mDfltElements[eHTMLTag_dir].mGroup.mBits.mList=1;
mDfltElements[eHTMLTag_dir].mIncludeKids=kDirKids;
mDfltElements[eHTMLTag_dir].mContainsGroups.mAllBits=0;
CElement::Initialize( mDfltElements[eHTMLTag_div], eHTMLTag_div, CBlockElement::GetGroup(), CFlowElement::GetContainedGroups());
CBlockElement::Initialize( mDfltElements[eHTMLTag_dl], eHTMLTag_dl);
mDfltElements[eHTMLTag_dl].mContainsGroups.mAllBits=0;
mDfltElements[eHTMLTag_dl].mIncludeKids=kDLKids;
CElement::Initialize( mDfltElements[eHTMLTag_dt], eHTMLTag_dt, CElement::GetEmptyGroup(), CInlineElement::GetContainedGroups());
mDfltElements[eHTMLTag_dt].mContainsGroups.mBits.mLeaf=1;
mDfltElements[eHTMLTag_dt].mAutoClose=kAutoCloseDD;
CPhraseElement::Initialize( mDfltElements[eHTMLTag_em], eHTMLTag_em);
CElement::Initialize( mDfltElements[eHTMLTag_embed], eHTMLTag_embed);
CBlockElement::Initialize( mDfltElements[eHTMLTag_endnote], eHTMLTag_endnote);
CElement::Initialize( mDfltElements[eHTMLTag_fieldset], eHTMLTag_fieldset, CBlockElement::GetGroup(), CFlowElement::GetContainedGroups());
mDfltElements[eHTMLTag_fieldset].mIncludeKids=kFieldsetKids;
CSpecialElement::Initialize( mDfltElements[eHTMLTag_font], eHTMLTag_font);
CElement::Initialize( mDfltElements[eHTMLTag_form], eHTMLTag_form, CBlockElement::GetGroup(), CBlockElement::GetBlockGroupMembers());
mDfltElements[eHTMLTag_form].mContainsGroups.mBits.mFormControl=1;
mDfltElements[eHTMLTag_form].mIncludeKids=kFormKids;
CElement::Initialize( mDfltElements[eHTMLTag_frame], eHTMLTag_frame, CFrameElement::GetGroup(), CLeafElement::GetContainedGroups());
mDfltElements[eHTMLTag_frame].mProperties.mIsContainer=0;
CFrameElement::Initialize( mDfltElements[eHTMLTag_frameset], eHTMLTag_frameset);
mDfltElements[eHTMLTag_frameset].mIncludeKids=kFramesetKids;
CElement::Initialize( mDfltElements[eHTMLTag_h1], eHTMLTag_h1, CBlockElement::GetGroup(), CBlockElement::GetContainedGroups(PR_FALSE));
CElement::Initialize( mDfltElements[eHTMLTag_h2], eHTMLTag_h2, CBlockElement::GetGroup(), CBlockElement::GetContainedGroups(PR_FALSE));
CElement::Initialize( mDfltElements[eHTMLTag_h3], eHTMLTag_h3, CBlockElement::GetGroup(), CBlockElement::GetContainedGroups(PR_FALSE));
CElement::Initialize( mDfltElements[eHTMLTag_h4], eHTMLTag_h4, CBlockElement::GetGroup(), CBlockElement::GetContainedGroups(PR_FALSE));
CElement::Initialize( mDfltElements[eHTMLTag_h5], eHTMLTag_h5, CBlockElement::GetGroup(), CBlockElement::GetContainedGroups(PR_FALSE));
CElement::Initialize( mDfltElements[eHTMLTag_h6], eHTMLTag_h6, CBlockElement::GetGroup(), CBlockElement::GetContainedGroups(PR_FALSE));
CElement::InitializeLeaf( mDfltElements[eHTMLTag_hr], eHTMLTag_hr, CBlockElement::GetGroup(), CLeafElement::GetContainedGroups());
CElement::Initialize( mDfltElements[eHTMLTag_head], eHTMLTag_head, CHeadElement::GetGroup(), CHeadElement::GetContainedGroups());
// InitializeElement( mDfltElements[eHTMLTag_head], eHTMLTag_html, CTopLevelElement::GetGroup(), CTopLevelElement::GetContainedGroups());
CFontStyleElement::Initialize( mDfltElements[eHTMLTag_i], eHTMLTag_i);
CElement::Initialize( mDfltElements[eHTMLTag_iframe], eHTMLTag_iframe, CSpecialElement::GetGroup(), CFlowElement::GetContainedGroups());
mDfltElements[eHTMLTag_iframe].mGroup.mBits.mBlock=1; //make this a member of the block group.
CElement::InitializeLeaf( mDfltElements[eHTMLTag_img], eHTMLTag_img, CSpecialElement::GetGroup(), CLeafElement::GetContainedGroups());
CElement::Initialize( mDfltElements[eHTMLTag_image], eHTMLTag_image);
CElement::InitializeLeaf( mDfltElements[eHTMLTag_input], eHTMLTag_input, CFormControlElement::GetGroup(),CLeafElement::GetContainedGroups());
CElement::Initialize( mDfltElements[eHTMLTag_ins], eHTMLTag_ins, CPhraseElement::GetGroup(), CFlowElement::GetContainedGroups());
mDfltElements[eHTMLTag_ins].mGroup.mBits.mBlock=1; //make this a member of the block group.
CElement::InitializeLeaf( mDfltElements[eHTMLTag_isindex], eHTMLTag_isindex, CBlockElement::GetGroup(), CLeafElement::GetContainedGroups());
CPhraseElement::Initialize( mDfltElements[eHTMLTag_kbd], eHTMLTag_kbd);
CDeprecatedElement::Initialize( mDfltElements[eHTMLTag_keygen], eHTMLTag_keygen);
CElement::Initialize( mDfltElements[eHTMLTag_label], eHTMLTag_label, CFormControlElement::GetGroup(), CInlineElement::GetContainedGroups());
mDfltElements[eHTMLTag_label].mContainsGroups.mBits.mSelf=0;
CElement::Initialize( mDfltElements[eHTMLTag_legend], eHTMLTag_legend, CElement::GetEmptyGroup(), CInlineElement::GetContainedGroups());
CElement::Initialize( mDfltElements[eHTMLTag_li], eHTMLTag_li, CListElement::GetGroup(), CFlowElement::GetContainedGroups());
mDfltElements[eHTMLTag_li].mExcludeKids=kLIExcludeKids;
mDfltElements[eHTMLTag_li].mContainsGroups.mBits.mSelf=0;
CElement::InitializeLeaf( mDfltElements[eHTMLTag_link], eHTMLTag_link, CHeadElement::GetMiscGroup(), CLeafElement::GetContainedGroups());
CElement::Initialize( mDfltElements[eHTMLTag_listing], eHTMLTag_listing);
CElement::Initialize( mDfltElements[eHTMLTag_map], eHTMLTag_map, CSpecialElement::GetGroup(), CBlockElement::GetBlockGroupMembers());
mDfltElements[eHTMLTag_map].mIncludeKids=kMapKids;
CBlockElement::Initialize( mDfltElements[eHTMLTag_menu], eHTMLTag_menu);
mDfltElements[eHTMLTag_menu].mGroup.mBits.mList=1;
mDfltElements[eHTMLTag_menu].mIncludeKids=kDirKids;
mDfltElements[eHTMLTag_menu].mContainsGroups.mAllBits=0;
CElement::InitializeLeaf( mDfltElements[eHTMLTag_meta], eHTMLTag_meta, CHeadElement::GetMiscGroup(), CLeafElement::GetContainedGroups());
CElement::Initialize( mDfltElements[eHTMLTag_multicol], eHTMLTag_multicol);
CElement::Initialize( mDfltElements[eHTMLTag_nobr], eHTMLTag_nobr);
CElement::Initialize( mDfltElements[eHTMLTag_noembed], eHTMLTag_noembed);
CElement::Initialize( mDfltElements[eHTMLTag_noframes], eHTMLTag_noframes, CBlockElement::GetGroup(), CFlowElement::GetContainedGroups());
CElement::Initialize( mDfltElements[eHTMLTag_noscript], eHTMLTag_noscript, CBlockElement::GetGroup(), CFlowElement::GetContainedGroups());
CElement::Initialize( mDfltElements[eHTMLTag_object], eHTMLTag_object, CBlockElement::GetGroup(), CFlowElement::GetContainedGroups());
mDfltElements[eHTMLTag_object].mGroup.mBits.mBlock=1; //make this a member of the block group.
mDfltElements[eHTMLTag_object].mGroup.mBits.mHeadMisc=1;
mDfltElements[eHTMLTag_object].mIncludeKids=kObjectKids;
CBlockElement::Initialize( mDfltElements[eHTMLTag_ol], eHTMLTag_ol);
mDfltElements[eHTMLTag_ol].mGroup.mBits.mList=1;
mDfltElements[eHTMLTag_ol].mIncludeKids=kDirKids;
mDfltElements[eHTMLTag_ol].mContainsGroups.mAllBits=0;
CElement::Initialize( mDfltElements[eHTMLTag_optgroup], eHTMLTag_optgroup, CElement::GetEmptyGroup(), CElement::GetEmptyGroup());
mDfltElements[eHTMLTag_optgroup].mContainsGroups.mAllBits=0;
mDfltElements[eHTMLTag_optgroup].mIncludeKids=kOptionGroupKids;
CElement::Initialize( mDfltElements[eHTMLTag_option], eHTMLTag_option, CElement::GetEmptyGroup(), CElement::GetEmptyGroup());
mDfltElements[eHTMLTag_option].mContainsGroups.mAllBits=0;
mDfltElements[eHTMLTag_option].mContainsGroups.mBits.mLeaf=1;
CElement::Initialize( mDfltElements[eHTMLTag_p], eHTMLTag_p, CBlockElement::GetGroup(), CInlineElement::GetContainedGroups());
mDfltElements[eHTMLTag_p].mContainsGroups.mBits.mSelf=0;
CElement::InitializeLeaf( mDfltElements[eHTMLTag_param], eHTMLTag_param, CElement::GetEmptyGroup(), CLeafElement::GetContainedGroups());
CBlockElement::Initialize( mDfltElements[eHTMLTag_pre], eHTMLTag_pre);
mDfltElements[eHTMLTag_pre].mExcludeKids=kPreExcludeKids;
CSpecialElement::Initialize( mDfltElements[eHTMLTag_q], eHTMLTag_q);
CFontStyleElement::Initialize( mDfltElements[eHTMLTag_s], eHTMLTag_s);
CPhraseElement::Initialize( mDfltElements[eHTMLTag_samp], eHTMLTag_samp );
CSpecialElement::Initialize( mDfltElements[eHTMLTag_script], eHTMLTag_script);
mDfltElements[eHTMLTag_script].mGroup.mBits.mBlock=1; //make this a member of the block group.
mDfltElements[eHTMLTag_script].mGroup.mBits.mHeadMisc=1;
CFormControlElement::Initialize( mDfltElements[eHTMLTag_select], eHTMLTag_select);
mDfltElements[eHTMLTag_select].mContainsGroups.mAllBits=0;
mDfltElements[eHTMLTag_select].mIncludeKids=kSelectKids;
CElement::Initialize( mDfltElements[eHTMLTag_server], eHTMLTag_server);
CFontStyleElement::Initialize( mDfltElements[eHTMLTag_small], eHTMLTag_small);
CElement::Initialize( mDfltElements[eHTMLTag_spacer], eHTMLTag_spacer);
CSpecialElement::Initialize( mDfltElements[eHTMLTag_span], eHTMLTag_span);
CFontStyleElement::Initialize( mDfltElements[eHTMLTag_strike], eHTMLTag_strike);
CPhraseElement::Initialize( mDfltElements[eHTMLTag_strong], eHTMLTag_strong);
CHeadElement::Initialize( mDfltElements[eHTMLTag_style], eHTMLTag_style);
CSpecialElement::Initialize( mDfltElements[eHTMLTag_sub], eHTMLTag_sub);
CSpecialElement::Initialize( mDfltElements[eHTMLTag_sup], eHTMLTag_sup);
CElement::Initialize( mDfltElements[eHTMLTag_table], eHTMLTag_table, CBlockElement::GetGroup(), CTableElement::GetContainedGroups());
CElement::Initialize( mDfltElements[eHTMLTag_tbody], eHTMLTag_tbody, CTableElement::GetGroup(), CLeafElement::GetContainedGroups());
mDfltElements[eHTMLTag_tbody].mIncludeKids=kTBodyKids;
CElement::Initialize( mDfltElements[eHTMLTag_td], eHTMLTag_td, CElement::GetEmptyGroup(), CFlowElement::GetContainedGroups());
mDfltElements[eHTMLTag_td].mContainsGroups.mBits.mSelf=0;
CElement::Initialize( mDfltElements[eHTMLTag_textarea], eHTMLTag_textarea);
CElement::Initialize( mDfltElements[eHTMLTag_tfoot], eHTMLTag_tfoot, CTableElement::GetGroup(), CLeafElement::GetContainedGroups());
mDfltElements[eHTMLTag_tfoot].mIncludeKids=kTBodyKids;
mDfltElements[eHTMLTag_tfoot].mContainsGroups.mBits.mSelf=0;
CElement::Initialize( mDfltElements[eHTMLTag_th], eHTMLTag_th, CElement::GetEmptyGroup(), CFlowElement::GetContainedGroups());
mDfltElements[eHTMLTag_th].mContainsGroups.mBits.mSelf=0;
CElement::Initialize( mDfltElements[eHTMLTag_thead], eHTMLTag_thead, CTableElement::GetGroup(), CLeafElement::GetContainedGroups());
mDfltElements[eHTMLTag_thead].mIncludeKids=kTBodyKids;
CTableRowElement::Initialize( mDfltElements[eHTMLTag_tr], eHTMLTag_tr);
mDfltElements[eHTMLTag_tr].mContainsGroups.mBits.mSelf=0;
CElement::Initialize( mDfltElements[eHTMLTag_title], eHTMLTag_title);
CFontStyleElement::Initialize( mDfltElements[eHTMLTag_tt], eHTMLTag_tt);
CFontStyleElement::Initialize( mDfltElements[eHTMLTag_u], eHTMLTag_u);
CBlockElement::Initialize( mDfltElements[eHTMLTag_ul], eHTMLTag_ul);
mDfltElements[eHTMLTag_ul].mGroup.mBits.mList=1;
mDfltElements[eHTMLTag_ul].mIncludeKids=kDirKids;
mDfltElements[eHTMLTag_ul].mContainsGroups.mAllBits=0;
CPhraseElement::Initialize( mDfltElements[eHTMLTag_var], eHTMLTag_var);
CElement::Initialize( mDfltElements[eHTMLTag_wbr], eHTMLTag_wbr);
CElement::Initialize( mDfltElements[eHTMLTag_xmp], eHTMLTag_xmp);
CLeafElement::Initialize( mDfltElements[eHTMLTag_text], eHTMLTag_text);
CLeafElement::Initialize( mDfltElements[eHTMLTag_comment], eHTMLTag_comment);
CLeafElement::Initialize( mDfltElements[eHTMLTag_newline], eHTMLTag_newline);
CLeafElement::Initialize( mDfltElements[eHTMLTag_whitespace],eHTMLTag_whitespace);
CLeafElement::Initialize( mDfltElements[eHTMLTag_unknown], eHTMLTag_unknown);
CElement::Initialize(mDfltElements[eHTMLTag_userdefined],
eHTMLTag_userdefined,
CElement::GetEmptyGroup(),
CFlowElement::GetContainedGroups()); // allow userdefined tag to contain anything.
mDfltElements[eHTMLTag_unknown].mIncludeKids=kUnknownKids;
/************************************************************
Now let's initialize the elements that we created directly
to handle special cases.
************************************************************/
mElements[eHTMLTag_body]=&mBodyElement;
mElements[eHTMLTag_frameset]=&mFramesetElement;
mElements[eHTMLTag_html]=&mHTMLElement;
mElements[eHTMLTag_script]=&mScriptElement;
mElements[eHTMLTag_style]=&mStyleElement;
mElements[eHTMLTag_title]=&mTitleElement;
mElements[eHTMLTag_textarea]=&mTextAreaElement;
mElements[eHTMLTag_pre]=&mPreElement;
mElements[eHTMLTag_table]=&mTableElement;
mElements[eHTMLTag_li]=&mLIElement;
mElements[eHTMLTag_applet]=&mAppletElement;
mElements[eHTMLTag_object]=&mObjectElement;
mElements[eHTMLTag_fieldset]=&mFieldsetElement;
mElements[eHTMLTag_counter]=&mCounterElement;
mElements[eHTMLTag_form]=&mFormElement;
mElements[eHTMLTag_head]=&mHeadElement;
}
#ifdef DEBUG
void CElementTable::DebugDumpGroups(CElement* aTag){
const PRUnichar* uctag=nsHTMLTags::GetStringValue(aTag->mTag);
const char* prefix=" ";
printf("\n\nTag: <%s>\n", NS_ConvertUCS2toUTF8(uctag).get());
printf(prefix);
if(aTag->IsContainer()) {
if(aTag->mContainsGroups.mBits.mHead) printf("head ");
if(aTag->mContainsGroups.mBits.mHeadMisc) printf("headmisc ");
if(aTag->mContainsGroups.mBits.mHeadContent) printf("headcontent ");
if(aTag->mContainsGroups.mBits.mTable) printf("table ");
if(aTag->mContainsGroups.mBits.mTextContainer) printf("text ");
if(aTag->mContainsGroups.mBits.mTopLevel) printf("toplevel ");
if(aTag->mContainsGroups.mBits.mDTDInternal) printf("internal ");
if(aTag->mContainsGroups.mBits.mFlowEntity) {
printf("block inline ");
}
else {
if (aTag->mContainsGroups.mBits.mBlockEntity) {
printf("blockEntity ");
}
if (aTag->mContainsGroups.mBits.mBlock) {
printf("block ");
}
if(aTag->mContainsGroups.mBits.mInlineEntity) {
printf("inline ");
}
else {
if(aTag->mContainsGroups.mBits.mFontStyle ) printf("fontstyle ");
if(aTag->mContainsGroups.mBits.mPhrase) printf("phrase ");
if(aTag->mContainsGroups.mBits.mSpecial) printf("special ");
if(aTag->mContainsGroups.mBits.mFormControl) printf("form ");
if(aTag->mContainsGroups.mBits.mHeading) printf("heading ");
if(aTag->mContainsGroups.mBits.mFrame) printf("frame ");
if(aTag->mContainsGroups.mBits.mList) printf("list ");
if(aTag->mContainsGroups.mBits.mPreformatted) printf("pre ");
if(aTag->mContainsGroups.mBits.mSelf) printf("self ");
if(aTag->mContainsGroups.mBits.mLeaf) printf("leaf ");
if(aTag->mContainsGroups.mBits.mWhiteSpace) printf("ws ");
if(aTag->mContainsGroups.mBits.mComment) printf("comment ");
}
}
if(aTag->mIncludeKids) {
printf("\n%s",prefix);
const eHTMLTags *theKid=aTag->mIncludeKids;
printf("+ ");
while(eHTMLTag_unknown!=*theKid){
const PRUnichar *t = nsHTMLTags::GetStringValue(*theKid++);
printf("%s ", NS_ConvertUCS2toUTF8(t).get());
}
}
if(aTag->mExcludeKids) {
printf("\n%s",prefix);
const eHTMLTags *theKid=aTag->mExcludeKids;
printf("- ");
while(eHTMLTag_unknown!=*theKid){
const PRUnichar *t = nsHTMLTags::GetStringValue(*theKid++);
printf("%s ", NS_ConvertUCS2toUTF8(t).get());
}
}
if(!aTag->mContainsGroups.mBits.mSelf){
printf("\n%s - self",prefix);
}
}
else {
printf("empty\n");
}
}
void CElementTable::DebugDumpContainment(CElement* anElement){
const PRUnichar *uctag = nsHTMLTags::GetStringValue(anElement->mTag);
const char* prefix=" ";
printf("\n\nTag: <%s>\n", NS_ConvertUCS2toUTF8(uctag).get());
printf(prefix);
int count=0;
int i=0;
for(i=0;i<NS_HTML_TAG_MAX;++i){
CElement* theChild=mElements[i];
if(anElement->CanContain(theChild,0)){
const PRUnichar *t = nsHTMLTags::GetStringValue(theChild->mTag);
printf("%s ", NS_ConvertUCS2toUTF8(t).get());
++count;
if(18==count) {
count=0;
printf("\n%s",prefix);
}
}
}
}
void CElementTable::DebugDumpInlineElements(const char* aTitle) {
PRInt32 theTagID=eHTMLTag_unknown;
PRBool result=PR_FALSE;
printf("Inline Elements -- %s: \n",aTitle);
while(theTagID<=eHTMLTag_userdefined) {
CElement *theTag=GetElement((eHTMLTags)theTagID);
if(theTag) {
result=theTag->IsInlineElement(eHTMLTag_unknown);
if(result) {
const PRUnichar *t = nsHTMLTags::GetStringValue(theTag->mTag);
printf(" %s\n", NS_ConvertUCS2toUTF8(t).get());
}
}
theTagID++;
}
}
void CElementTable::DebugDumpBlockElements(const char* aTitle) {
PRInt32 theTagID=eHTMLTag_unknown;
PRBool result=PR_FALSE;
printf("Block Elements -- %s: \n",aTitle);
while(theTagID<=eHTMLTag_userdefined) {
CElement *theTag=GetElement((eHTMLTags)theTagID);
if(theTag) {
result=theTag->IsBlockElement(eHTMLTag_unknown);
if(result) {
const PRUnichar *theName = nsHTMLTags::GetStringValue(theTag->mTag);
printf(" %s\n", NS_ConvertUCS2toUTF8(theName).get());
}
}
theTagID++;
}
}
void CElementTable::DebugDumpContainment(const char* aTitle){
#if 0
DebugDumpContainment(mElements[eHTMLTag_head]);
DebugDumpContainment(mElements[eHTMLTag_html]);
DebugDumpContainment(mElements[eHTMLTag_table]);
printf("\n");
#endif
printf("==================================================\n");
printf("%s\n",aTitle);
printf("==================================================\n");
int i=0;
for(i=1;i<NS_HTML_TAG_MAX;++i){
DebugDumpContainment(mElements[i]);
//DebugDumpGroups(mElements[i]);
} //for
}
#endif
/******************************************************************************
Yes, I know it's inconvenient to find this methods here, but it's easier
for the compiler -- and making it's life easier is my top priority.
******************************************************************************/
PRInt32 CElement::FindAutoCloseIndexForStartTag(CElement* anElement,PRInt32 aParentIndex,nsDTDContext* aContext) {
PRInt32 result=kNotFound;
if(anElement) {
eHTMLTags theParentTag=aContext->TagAt(aParentIndex);
if(eHTMLTag_unknown!=theParentTag) {
CElement* theParent=gElementTable->mElements[theParentTag];
if(!theParent->CanContain(anElement,aContext)) {
if(HasOptionalEndTag(theParentTag)) {
if(ListContainsTag(theParent->mAutoClose,anElement->mTag)) {
result=theParent->FindAutoCloseIndexForStartTag(anElement,aParentIndex-1,aContext);
}
else if((theParent->mTag==anElement->mTag) && (!theParent->mContainsGroups.mBits.mSelf)){
result=aParentIndex;
}
else if(eHTMLTag_body!=theParent->mTag) {
result=theParent->FindAutoCloseIndexForStartTag(anElement,aParentIndex-1,aContext);
}
else result=aParentIndex+1;
}
else result=kNotFound;
}
else result=aParentIndex+1;
}
}
return result;
}
/******************************************************************************
Yes, I know it's inconvenient to find this methods here, but it's easier
for the compiler -- and making it's life easier is my top priority.
******************************************************************************/
PRBool CElement::CanBeClosedByEndTag(CElement* anElement,nsDTDContext* aContext) {
PRBool result=PR_FALSE;
//first, let's see if we can contain the given tag based on group info...
if(anElement) {
if(ListContainsTag(mAutoClose,anElement->mTag)) {
return PR_TRUE;
}
else if((this==anElement) && (!mContainsGroups.mBits.mSelf)){
return PR_TRUE;
}
else {
eHTMLTags theTag=aContext->Last();
CElement* theElement=gElementTable->mElements[theTag];
if(HasOptionalEndTag(theTag)) {
if(anElement->CanContain(theElement,aContext)){
result=PR_TRUE;
}
}
}
}
return result;
}
/******************************************************************************
Yes, I know it's inconvenient to find this methods here, but it's easier
for the compiler -- and making it's life easier is my top priority.
******************************************************************************/
PRBool CElement::CanContain(CElement* anElement,nsDTDContext* aContext) {
PRBool result=PR_FALSE;
//first, let's see if we can contain the given tag based on group info...
if(anElement) {
if(!anElement->mProperties.mDeprecated) {
if(anElement!=this) {
if(ListContainsTag(mExcludeKids,anElement->mTag)) {
return PR_FALSE;
}
else if(ContainsGroup(mContainsGroups,anElement->mGroup)) {
result=PR_TRUE;
}
else if(ListContainsTag(mIncludeKids,anElement->mTag)) {
return PR_TRUE;
}
}
else result=mContainsGroups.mBits.mSelf;
}
/***************************************************
This is a (cheesy) exception table, that allows
us to override containment for transitional
documents. A better implementation would be to
create unique classes for each of the tags in
this table, and to override CanContain() there.
***************************************************/
if((!result) && (aContext->mFlags.mTransitional)) {
switch(mTag) {
case eHTMLTag_address:
if(eHTMLTag_p==anElement->mTag)
result=PR_TRUE;
break;
case eHTMLTag_blockquote:
case eHTMLTag_form:
case eHTMLTag_iframe:
result=ContainsGroup(CFlowElement::GetContainedGroups(),anElement->mGroup);
break;
case eHTMLTag_button:
if((eHTMLTag_iframe==anElement->mTag) || (eHTMLTag_isindex==anElement->mTag))
result=PR_TRUE;
break;
default:
break;
}
}
}
return result;
}
nsresult CElement::WillHandleStartToken( CElement *anElement,
nsIParserNode* aNode,
eHTMLTags aTag,
nsDTDContext* aContext,
nsIHTMLContentSink* aSink) {
nsresult result=NS_OK;
return result;
}
nsresult CElement::HandleStartToken( nsCParserNode* aNode,
eHTMLTags aTag,
nsDTDContext* aContext,
nsIHTMLContentSink* aSink) {
CElement* theElement=gElementTable->mElements[aTag];
nsresult result=WillHandleStartToken(theElement,aNode,aTag,aContext,aSink);
#if 0
CElement* theDelegate=theElement->GetDelegate();
if(theDelegate) {
result=theDelegate->HandleStartToken(aNode,aTag,aContext,aSink);
}
else
#endif
{
if(theElement) {
if(CanContain(theElement,aContext)) {
if(theElement->IsContainer()) {
if(theElement->IsSinkContainer()) {
result=theElement->OpenContainerInContext(aNode,aTag,aContext,aSink);
}
else {
result=theElement->OpenContext(aNode,aTag,aContext,aSink);
}
}
else {
result=aSink->AddLeaf(*aNode);
}
}
else if(theElement->IsBlockCloser()){
//Ok, so we have a start token that is misplaced. Before handing this off
//to a default container (parent), let's check the autoclose condition.
if(HasOptionalEndTag(mTag)) {
//aha! We have a case where this tag is autoclosed by anElement.
//Let's close this container, then try to open theElement.
PRInt32 theCount=aContext->GetCount();
PRInt32 theIndex=FindAutoCloseIndexForStartTag(theElement,theCount-2,aContext);
//continue ripping code out here...
if(kNotFound!=theIndex) {
eHTMLTags theParentTag=eHTMLTag_unknown;
CElement* theParent=0;
while(NS_SUCCEEDED(result) && (theCount>theIndex)) {
theParentTag=aContext->Last();
theParent=gElementTable->mElements[theParentTag];
nsCParserNode *theNode=aContext->PeekNode(); //this will get popped later...
if(theParent->IsSinkContainer()) {
CloseContainerInContext(theNode,theParentTag,aContext,aSink);
}
else CloseContext(theNode,theParentTag,aContext,aSink);
theCount--;
}
if(NS_SUCCEEDED(result)){
theParentTag=aContext->Last();
theParent=gElementTable->mElements[theParentTag];
result=theParent->HandleStartToken(aNode,aTag,aContext,aSink);
}
}
return result;
}
else {
PRBool theElementCanOpen=PR_FALSE;
//the logic here is simple:
// This operation can only succeed if the given tag is open, AND
// all the tags below it have optional end tags.
// If these conditions aren't met, we bail out, leaving the tag open.
if(mTag!=aTag) {
PRInt32 theLastPos=aContext->LastOf(aTag); //see if it's already open...
if(-1!=theLastPos) {
PRInt32 theCount=aContext->GetCount();
result=HandleEndToken(aNode,aTag,aContext,aSink);
theElementCanOpen=PRBool(aContext->GetCount()<theCount);
}
}
if(theElementCanOpen) {
if(NS_SUCCEEDED(result)){
eHTMLTags theParentTag=aContext->Last();
CElement* theParent=gElementTable->mElements[theParentTag];
return theParent->HandleStartToken(aNode,aTag,aContext,aSink);
}
}
}
//ok, here's our last recourse -- let's let the parent handle it.
CElement* theContainer=GetDefaultContainerFor(theElement);
if(theContainer) {
result=theContainer->HandleMisplacedStartToken(aNode,aTag,aContext,aSink);
}
}
}
}
return result;
}
nsresult CElement::HandleEndToken(nsCParserNode* aNode,eHTMLTags aTag,nsDTDContext* aContext,nsIHTMLContentSink* aSink) {
nsresult result=NS_OK;
if(aContext->Last()==aTag) {
CElement* theElement=gElementTable->mElements[aTag];
if(theElement) {
if(theElement->IsSinkContainer()) {
result=CloseContainerInContext(aNode,aTag,aContext,aSink);
}
else result=CloseContext(aNode,aTag,aContext,aSink);
return result;
}
}
PRInt32 theCount=aContext->GetCount();
PRInt32 theIndex=theCount-1;
PRInt32 theCloseTarget=FindAutoCloseTargetForEndTag(aNode,aTag,aContext,aSink,theIndex);
if(-1!=theCloseTarget) {
while(theCloseTarget<theCount) {
eHTMLTags theTag=aContext->Last();
eHTMLTags theGrandParentTag=aContext->TagAt(theCount-2);
CElement *theGrandParent=GetElement(theGrandParentTag);
result=theGrandParent->HandleEndToken(aNode,theTag,aContext,aSink);
theCount--;
}
//return result;
}
return result;
}
inline CElement* CElement::GetDelegate(void) {
if(eHTMLTag_unknown!=mDelegate) {
return gElementTable->mElements[mDelegate];
}
return 0;
}
inline CElement* CElement::GetDefaultContainerFor(CElement* anElement) {
CElement* result=0;
if(anElement) {
if(anElement->mGroup.mBits.mBlock) {
result=gElementTable->mElements[eHTMLTag_body];
}
else if(anElement->mGroup.mBits.mHeadContent) {
result=gElementTable->mElements[eHTMLTag_head];
}
else if(anElement->mGroup.mBits.mHeadMisc) {
result=gElementTable->mElements[eHTMLTag_head];
}
}
return result;
}
//this tells us whether this tag is a block tag within the given parent
//NOTE: aParentID is currently ignored, but shouldn't be.
PRBool CElement::IsBlockElement(eHTMLTags aParentID) {
CGroupMembers& theBlockGroup=CBlockElement::GetBlockGroupMembers();
PRBool result=ContainsGroup(theBlockGroup,mGroup);
return result;
}
//this tells us whether this tag is an inline tag within the given parent
//NOTE: aParentID is currently ignored, but shouldn't be.
PRBool CElement::IsInlineElement(eHTMLTags aParentID) {
CGroupMembers& theInlineGroup=CInlineElement::GetContainedGroups();
PRBool result=ContainsGroup(theInlineGroup,mGroup);
return result;
}
#endif