/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* * The contents of this file are subject to the Netscape 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/NPL/ * * 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 Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): */ /** * MODULE NOTES: * @update gess 4/1/98 * */ #include "nsElementTable.h" /** * * @update gess 01/04/99 * @param * @return */ PRInt32 GetTopmostIndexOf(nsDTDContext& aContext,TagList& aTagList){ int max = aContext.GetCount(); int index; for(index=max-1;index>=0;index--){ PRBool result=FindTagInSet(aContext[index],aTagList.mTags,aTagList.mCount); if(result) { return index; } } return kNotFound; } /** * * @update gess 01/04/99 * @param * @return */ PRInt32 GetBottommostIndexOf(nsDTDContext& aContext,PRInt32 aStartOffset,TagList& aTagList){ int max = aContext.GetCount(); int index; for(index=aStartOffset;index=eHTMLTag_unknown) & (aTag<=eHTMLTag_userdefined)){ result=TestBits(gHTMLElements[aTag].mParentBits,kBlockEntity); } return result; } /** * * @update gess 01/04/99 * @param * @return */ PRBool nsHTMLElement::IsBlockCloser(eHTMLTags aTag){ PRBool result=PR_FALSE; if((aTag>=eHTMLTag_unknown) & (aTag<=eHTMLTag_userdefined)){ // result=IsFlowElement(aTag); result=gHTMLElements[aTag].IsMemberOf(kBlockEntity); //was kFlowEntity... if(!result) { static eHTMLTags gClosers[]={ eHTMLTag_table,eHTMLTag_tbody,eHTMLTag_caption,eHTMLTag_dd,eHTMLTag_dt, eHTMLTag_td,eHTMLTag_tfoot,eHTMLTag_th,eHTMLTag_thead,eHTMLTag_tr, eHTMLTag_optgroup}; result=FindTagInSet(aTag,gClosers,sizeof(gClosers)/sizeof(eHTMLTag_body)); } } return result; } /** * * @update gess 01/04/99 * @param * @return */ PRBool nsHTMLElement::IsInlineEntity(eHTMLTags aTag){ PRBool result=PR_FALSE; if((aTag>=eHTMLTag_unknown) & (aTag<=eHTMLTag_userdefined)){ result=TestBits(gHTMLElements[aTag].mParentBits,kInlineEntity); } return result; } /** * * @update gess 01/04/99 * @param * @return */ PRBool nsHTMLElement::IsFlowEntity(eHTMLTags aTag){ PRBool result=PR_FALSE; if((aTag>=eHTMLTag_unknown) & (aTag<=eHTMLTag_userdefined)){ result=TestBits(gHTMLElements[aTag].mParentBits,kFlowEntity); } return result; } /** * * @update gess 01/04/99 * @param * @return */ PRBool nsHTMLElement::IsBlockParent(eHTMLTags aTag){ PRBool result=PR_FALSE; if((aTag>=eHTMLTag_unknown) & (aTag<=eHTMLTag_userdefined)){ result=TestBits(gHTMLElements[aTag].mInclusionBits,kBlockEntity); } return result; } /** * * @update gess 01/04/99 * @param * @return */ PRBool nsHTMLElement::IsInlineParent(eHTMLTags aTag){ PRBool result=PR_FALSE; if((aTag>=eHTMLTag_unknown) & (aTag<=eHTMLTag_userdefined)){ result=TestBits(gHTMLElements[aTag].mInclusionBits,kInlineEntity); } return result; } /** * * @update gess 01/04/99 * @param * @return */ PRBool nsHTMLElement::IsFlowParent(eHTMLTags aTag){ PRBool result=PR_FALSE; if((aTag>=eHTMLTag_unknown) & (aTag<=eHTMLTag_userdefined)){ result=TestBits(gHTMLElements[aTag].mInclusionBits,kFlowEntity); } return result; } /** * * @update harishd 11/19/99 * @param * @return */ PRBool nsHTMLElement::IsSpecialParent(eHTMLTags aTag) const{ PRBool result=PR_FALSE; if(mSpecialParents) { if(FindTagInSet(aTag,mSpecialParents->mTags,mSpecialParents->mCount)) result=PR_TRUE; } return result; } /** * Tells us whether the given tag opens a section * @update gess 01/04/99 * @param id of tag * @return TRUE if opens section */ PRBool nsHTMLElement::IsSectionTag(eHTMLTags aTag){ PRBool result=PR_FALSE; switch(aTag){ case eHTMLTag_html: case eHTMLTag_frameset: case eHTMLTag_body: case eHTMLTag_head: result=PR_TRUE; break; default: result=PR_FALSE; } return result; } /** * * @update gess 01/04/99 * @param * @return */ PRBool nsHTMLElement::CanContain(eHTMLTags aParent,eHTMLTags aChild){ PRBool result=PR_FALSE; if((aParent>=eHTMLTag_unknown) & (aParent<=eHTMLTag_userdefined)){ result=gHTMLElements[aParent].CanContain(aChild); } return result; } /** * * @update gess 01/04/99 * @param * @return */ PRBool nsHTMLElement::CanExclude(eHTMLTags aChild) const{ PRBool result=PR_FALSE; //Note that special kids takes precedence over exclusions... if(mSpecialKids) { if(FindTagInSet(aChild,mSpecialKids->mTags,mSpecialKids->mCount)) { return PR_FALSE; } } if(eHTMLTag_unknown!=mExclusionBits){ if(gHTMLElements[aChild].IsMemberOf(mExclusionBits)) { result=PR_TRUE; } } return result; } /** * * @update gess 01/04/99 * @param * @return */ PRBool nsHTMLElement::CanOmitEndTag(void) const{ PRBool result=!IsContainer(mTagID); if(!result) result=TestBits(mSpecialProperties,kOmitEndTag); return result; } /** * * @update gess 01/04/99 * @param * @return */ PRBool nsHTMLElement::CanOmitStartTag(eHTMLTags aChild) const{ PRBool result=PR_FALSE; return result; } /** * * @update gess12/13/98 * @param * @return */ PRBool nsHTMLElement::IsChildOfHead(eHTMLTags aChild) { PRBool result=FindTagInSet(aChild,gHeadKids.mTags,gHeadKids.mCount); return result; } /** * * @update gess12/13/98 * @param * @return */ PRBool nsHTMLElement::SectionContains(eHTMLTags aChild,PRBool allowDepthSearch) { PRBool result=PR_FALSE; TagList* theRootTags=gHTMLElements[aChild].GetRootTags(); if(theRootTags){ if(!FindTagInSet(mTagID,theRootTags->mTags,theRootTags->mCount)){ eHTMLTags theRootBase=GetTagAt(0,*theRootTags); if((eHTMLTag_unknown!=theRootBase) && (allowDepthSearch)) result=SectionContains(theRootBase,allowDepthSearch); } else result=PR_TRUE; } return result; } /** * * @update gess12/13/98 * @param * @return */ PRBool nsHTMLElement::IsStyleTag(eHTMLTags aChild) { PRBool result=PR_FALSE; switch(aChild) { case eHTMLTag_a: // case eHTMLTag_abbr: // case eHTMLTag_acronym: case eHTMLTag_b: case eHTMLTag_bdo: case eHTMLTag_big: case eHTMLTag_blink: // case eHTMLTag_center: // case eHTMLTag_cite: // case eHTMLTag_code: case eHTMLTag_del: // case eHTMLTag_dfn: // case eHTMLTag_em: case eHTMLTag_font: case eHTMLTag_i: case eHTMLTag_ins: // case eHTMLTag_kbd: case eHTMLTag_q: case eHTMLTag_s: // case eHTMLTag_samp: case eHTMLTag_small: case eHTMLTag_span: case eHTMLTag_strike: // case eHTMLTag_strong: case eHTMLTag_sub: case eHTMLTag_sup: case eHTMLTag_tt: case eHTMLTag_u: // case eHTMLTag_var: result=PR_TRUE; default: break; }; return result; } /** * * @update gess12/13/98 * @param * @return */ PRBool nsHTMLElement::IsHeadingTag(eHTMLTags aChild) { return FindTagInSet(aChild,gHeadingTags.mTags,gHeadingTags.mCount); } /** * * @update gess12/13/98 * @param * @return */ PRBool nsHTMLElement::CanContainType(PRInt32 aType) const{ PRInt32 answer=mInclusionBits & aType; PRBool result=PRBool(0!=answer); return result; } /** * * @update gess12/13/98 * @param * @return */ PRBool nsHTMLElement::IsMemberOf(PRInt32 aSet) const{ PRBool result=(aSet && TestBits(aSet,mParentBits)); return result; } /** * * @update gess12/13/98 * @param * @return */ PRBool nsHTMLElement::IsWhitespaceTag(eHTMLTags aChild) { PRBool result=PR_FALSE; switch(aChild) { case eHTMLTag_newline: case eHTMLTag_whitespace: result=PR_TRUE; break; default: break; } return result; } /** * * @update gess12/13/98 * @param * @return */ PRBool nsHTMLElement::IsTextTag(eHTMLTags aChild) { PRBool result=PR_FALSE; switch(aChild) { case eHTMLTag_text: case eHTMLTag_entity: case eHTMLTag_newline: case eHTMLTag_whitespace: result=PR_TRUE; break; default: break; } return result; } /** * * @update gess12/13/98 * @param * @return */ PRBool nsHTMLElement::CanContainSelf(void) const { PRBool result=PRBool(TestBits(mInclusionBits,kSelf)!=0); return result; } /** * * @update harishd 09/20/99 * @param * @return */ PRBool nsHTMLElement::CanAutoCloseTag(eHTMLTags aTag) const{ PRBool result=PR_TRUE; if((mTagID>=eHTMLTag_unknown) & (mTagID<=eHTMLTag_userdefined)) { TagList* theTagList=gHTMLElements[mTagID].mDontAutocloseEnd; if(theTagList) { result=!FindTagInSet(aTag,theTagList->mTags,theTagList->mCount); } } return result; } /** * * @update gess12/13/98 * @param * @return */ eHTMLTags nsHTMLElement::GetCloseTargetForEndTag(nsDTDContext& aContext,PRInt32 anIndex) const{ eHTMLTags result=eHTMLTag_unknown; int theCount=aContext.GetCount(); int theIndex=theCount; if(IsMemberOf(kPhrase)){ while((--theIndex>=anIndex) && (eHTMLTag_unknown==result)){ eHTMLTags theTag=aContext.TagAt(theIndex); if(theTag!=mTagID) { //phrasal elements can close other phrasals, along with fontstyle and special tags... if(!gHTMLElements[theTag].IsMemberOf(kSpecial|kFontStyle|kPhrase)) { break; //it's not something I can close } } else { result=theTag; //stop because you just found yourself on the stack break; } } } else if(IsMemberOf(kSpecial)){ while((--theIndex>=anIndex) && (eHTMLTag_unknown==result)){ eHTMLTags theTag=aContext.TagAt(theIndex); if(theTag!=mTagID) { //phrasal elements can close other phrasals, along with fontstyle and special tags... if(gHTMLElements[theTag].IsMemberOf(kSpecial) || gHTMLElements[theTag].IsMemberOf(kFontStyle)){ } else { break; //it's not something I can close } } else { result=theTag; //stop because you just found yourself on the stack break; } } } else if(IsMemberOf(kFormControl|kExtensions)){ while((--theIndex>=anIndex) && (eHTMLTag_unknown==result)){ eHTMLTags theTag=aContext.TagAt(theIndex); if(theTag!=mTagID) { if(!CanContain(theTag)) { break; //it's not something I can close } } else { result=theTag; //stop because you just found yourself on the stack break; } } } else if(IsStyleTag(mTagID)){ eHTMLTags theTag=aContext.Last(); if(IsStyleTag(theTag)) { result=theTag; } } return result; } /** * See whether this tag can DIRECTLY contain the given child. * @update gess12/13/98 * @param * @return */ PRBool nsHTMLElement::CanContain(eHTMLTags aChild) const{ if(IsContainer(mTagID)){ if(gHTMLElements[aChild].HasSpecialProperty(kLegalOpen)) { // Some tags could be opened anywhere, in the document, as they please. return PR_TRUE; } if(mTagID==aChild) { return CanContainSelf(); //not many tags can contain themselves... } TagList* theCloseTags=gHTMLElements[aChild].GetAutoCloseStartTags(); if(theCloseTags){ if(FindTagInSet(mTagID,theCloseTags->mTags,theCloseTags->mCount)) return PR_FALSE; } if(nsHTMLElement::IsBlockEntity(aChild)){ if(nsHTMLElement::IsBlockParent(mTagID)){ return PR_TRUE; } } if(nsHTMLElement::IsInlineEntity(aChild)){ if(nsHTMLElement::IsInlineParent(mTagID)){ return PR_TRUE; } } if(nsHTMLElement::IsFlowEntity(aChild)) { if(nsHTMLElement::IsFlowParent(mTagID)){ return PR_TRUE; } } if(nsHTMLElement::IsTextTag(aChild)) { if(nsHTMLElement::IsInlineParent(mTagID)){ return PR_TRUE; } } if(CanContainType(gHTMLElements[aChild].mParentBits)) { return PR_TRUE; } if(mSpecialKids) { if(FindTagInSet(aChild,mSpecialKids->mTags,mSpecialKids->mCount)) { return PR_TRUE; } } } return PR_FALSE; } void nsHTMLElement::DebugDumpContainment(const char* aFilename,const char* aTitle){ #ifdef RICKG_DEBUG PRBool t=CanContain(eHTMLTag_address,eHTMLTag_object); const char* prefix=" "; fstream out(aFilename,ios::out); out << "==================================================" << endl; out << aTitle << endl; out << "=================================================="; int i,j=0; int written; int linenum=5; for(i=1;i" << endl; out << prefix; linenum+=3; written=0; char startChar=0; if(IsContainer((eHTMLTags)i)) { for(j=1;j