910 lines
26 KiB
C++
910 lines
26 KiB
C++
/* -*- 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.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
|
|
/**
|
|
* MODULE NOTES:
|
|
* @update gess 4/8/98
|
|
*
|
|
*
|
|
*/
|
|
|
|
#include "CNavDTD.h"
|
|
#include "nsHTMLTokens.h"
|
|
#include "nsCRT.h"
|
|
#include "nsParserTypes.h"
|
|
#include "nsIParser.h"
|
|
|
|
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
|
|
static NS_DEFINE_IID(kIDTDIID, NS_IDTD_IID);
|
|
static NS_DEFINE_IID(kClassIID, NS_INAVHTML_DTD_IID);
|
|
|
|
|
|
/**
|
|
* This method gets called as part of our COM-like interfaces.
|
|
* Its purpose is to create an interface to parser object
|
|
* of some type.
|
|
*
|
|
* @update gess 4/8/98
|
|
* @param nsIID id of object to discover
|
|
* @param aInstancePtr ptr to newly discovered interface
|
|
* @return NS_xxx result code
|
|
*/
|
|
nsresult CNavDTD::QueryInterface(const nsIID& aIID, void** aInstancePtr)
|
|
{
|
|
if (NULL == aInstancePtr) {
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
|
|
if(aIID.Equals(kISupportsIID)) { //do IUnknown...
|
|
*aInstancePtr = (nsIDTD*)(this);
|
|
}
|
|
else if(aIID.Equals(kIDTDIID)) { //do IParser base class...
|
|
*aInstancePtr = (nsIDTD*)(this);
|
|
}
|
|
else if(aIID.Equals(kClassIID)) { //do this class...
|
|
*aInstancePtr = (CNavDTD*)(this);
|
|
}
|
|
else {
|
|
*aInstancePtr=0;
|
|
return NS_NOINTERFACE;
|
|
}
|
|
((nsISupports*) *aInstancePtr)->AddRef();
|
|
return NS_OK;
|
|
}
|
|
|
|
/**
|
|
* This method is defined in nsIParser. It is used to
|
|
* cause the COM-like construction of an nsHTMLParser.
|
|
*
|
|
* @update gess 4/8/98
|
|
* @param nsIParser** ptr to newly instantiated parser
|
|
* @return NS_xxx error result
|
|
*/
|
|
NS_HTMLPARS nsresult NS_NewNavHTMLDTD(nsIDTD** aInstancePtrResult)
|
|
{
|
|
CNavDTD* it = new CNavDTD();
|
|
|
|
if (it == 0) {
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
return it->QueryInterface(kClassIID, (void **) aInstancePtrResult);
|
|
}
|
|
|
|
|
|
NS_IMPL_ADDREF(CNavDTD)
|
|
NS_IMPL_RELEASE(CNavDTD)
|
|
|
|
|
|
/**
|
|
* Default constructor
|
|
*
|
|
* @update gess 4/9/98
|
|
* @param
|
|
* @return
|
|
*/
|
|
CNavDTD::CNavDTD() : nsIDTD() {
|
|
mParser=0;
|
|
}
|
|
|
|
/**
|
|
* Default destructor
|
|
*
|
|
* @update gess 4/9/98
|
|
* @param
|
|
* @return
|
|
*/
|
|
CNavDTD::~CNavDTD(){
|
|
}
|
|
|
|
/**
|
|
*
|
|
*
|
|
* @update gess 3/25/98
|
|
* @param
|
|
* @return
|
|
*/
|
|
void CNavDTD::SetParser(nsIParser* aParser) {
|
|
mParser=aParser;
|
|
}
|
|
|
|
|
|
static char formElementTags[]= {
|
|
eHTMLTag_button, eHTMLTag_fieldset, eHTMLTag_input,
|
|
eHTMLTag_isindex, eHTMLTag_label, eHTMLTag_legend,
|
|
eHTMLTag_select, eHTMLTag_textarea,0};
|
|
|
|
static char gHeadingTags[]={
|
|
eHTMLTag_h1, eHTMLTag_h2, eHTMLTag_h3,
|
|
eHTMLTag_h4, eHTMLTag_h5, eHTMLTag_h6,
|
|
0};
|
|
|
|
|
|
/**
|
|
* This method is called to determine whether or not a tag
|
|
* of one type can contain a tag of another type.
|
|
*
|
|
* @update gess 4/8/98
|
|
* @param aParent -- tag enum of parent container
|
|
* @param aChild -- tag enum of child container
|
|
* @return PR_TRUE if parent can contain child
|
|
*/
|
|
PRBool CNavDTD::CanContainFormElement(PRInt32 aParent,PRInt32 aChild) const {
|
|
PRBool result=(mParser) ? mParser->HasOpenContainer(eHTMLTag_form) : PR_FALSE;
|
|
return result;
|
|
}
|
|
|
|
|
|
/**
|
|
* This method is called to determine whether or not a tag
|
|
* of one type can contain a tag of another type.
|
|
*
|
|
* @update gess 4/8/98
|
|
* @param aParent -- tag enum of parent container
|
|
* @param aChild -- tag enum of child container
|
|
* @return PR_TRUE if parent can contain child
|
|
*/
|
|
PRBool CNavDTD::CanContain(PRInt32 aParent,PRInt32 aChild) const {
|
|
|
|
PRBool result=PR_FALSE;
|
|
|
|
//tagset1 has 64 members...
|
|
static char gTagSet1[]={
|
|
eHTMLTag_a, eHTMLTag_acronym, eHTMLTag_address, eHTMLTag_applet,
|
|
eHTMLTag_bold, eHTMLTag_basefont, eHTMLTag_bdo, eHTMLTag_big,
|
|
eHTMLTag_blockquote,eHTMLTag_br, eHTMLTag_button, eHTMLTag_center,
|
|
eHTMLTag_cite, eHTMLTag_code, eHTMLTag_dfn, eHTMLTag_dir,
|
|
eHTMLTag_div, eHTMLTag_dl, eHTMLTag_em, eHTMLTag_fieldset,
|
|
eHTMLTag_font, eHTMLTag_form, eHTMLTag_h1, eHTMLTag_h2,
|
|
eHTMLTag_h3, eHTMLTag_h4, eHTMLTag_h5, eHTMLTag_h6,
|
|
eHTMLTag_hr, eHTMLTag_italic, eHTMLTag_iframe, eHTMLTag_img,
|
|
eHTMLTag_input, eHTMLTag_isindex,
|
|
|
|
eHTMLTag_kbd, eHTMLTag_label,
|
|
eHTMLTag_map, eHTMLTag_menu, eHTMLTag_newline, //JUST ADDED!
|
|
eHTMLTag_noframes, eHTMLTag_noscript,
|
|
eHTMLTag_object, eHTMLTag_ol, eHTMLTag_paragraph, eHTMLTag_pre,
|
|
eHTMLTag_quotation, eHTMLTag_strike, eHTMLTag_samp, eHTMLTag_script,
|
|
eHTMLTag_select, eHTMLTag_small, eHTMLTag_span, eHTMLTag_strong,
|
|
eHTMLTag_sub, eHTMLTag_sup, eHTMLTag_table, eHTMLTag_text,
|
|
|
|
eHTMLTag_textarea, eHTMLTag_tt, eHTMLTag_u, eHTMLTag_ul,
|
|
eHTMLTag_userdefined, eHTMLTag_var,
|
|
eHTMLTag_whitespace, //JUST ADDED!
|
|
0};
|
|
|
|
//tagset2 has 43 members...
|
|
static char gTagSet2[]={
|
|
eHTMLTag_a, eHTMLTag_acronym, eHTMLTag_applet, eHTMLTag_bold,
|
|
eHTMLTag_basefont, eHTMLTag_bdo, eHTMLTag_big, eHTMLTag_br,
|
|
eHTMLTag_button, eHTMLTag_cite, eHTMLTag_code, eHTMLTag_dfn,
|
|
eHTMLTag_em, eHTMLTag_font, eHTMLTag_hr, eHTMLTag_italic,
|
|
eHTMLTag_iframe, eHTMLTag_img, eHTMLTag_input, eHTMLTag_kbd,
|
|
|
|
eHTMLTag_label, eHTMLTag_map, eHTMLTag_newline, //JUST ADDED!
|
|
eHTMLTag_object, eHTMLTag_paragraph,
|
|
eHTMLTag_quotation, eHTMLTag_strike, eHTMLTag_samp, eHTMLTag_script,
|
|
eHTMLTag_select, eHTMLTag_small, eHTMLTag_span, eHTMLTag_strong,
|
|
eHTMLTag_sub, eHTMLTag_sup, eHTMLTag_text, eHTMLTag_textarea,
|
|
eHTMLTag_tt, eHTMLTag_u, eHTMLTag_userdefined, eHTMLTag_var,
|
|
eHTMLTag_whitespace,//JUST ADDED!
|
|
0};
|
|
|
|
//tagset3 has 57 members...
|
|
static char gTagSet3[]={
|
|
eHTMLTag_a, eHTMLTag_acronym, eHTMLTag_applet, eHTMLTag_bold,
|
|
eHTMLTag_bdo, eHTMLTag_big, eHTMLTag_br, eHTMLTag_blockquote,
|
|
eHTMLTag_body, eHTMLTag_caption, eHTMLTag_center, eHTMLTag_cite,
|
|
eHTMLTag_code, eHTMLTag_dd, eHTMLTag_del, eHTMLTag_dfn,
|
|
eHTMLTag_div, eHTMLTag_dt, eHTMLTag_em, eHTMLTag_fieldset,
|
|
eHTMLTag_font, eHTMLTag_form, eHTMLTag_h1, eHTMLTag_h2,
|
|
eHTMLTag_h3, eHTMLTag_h4, eHTMLTag_h5, eHTMLTag_h6,
|
|
eHTMLTag_italic, eHTMLTag_iframe, eHTMLTag_ins, eHTMLTag_kbd,
|
|
|
|
eHTMLTag_label, eHTMLTag_legend,
|
|
eHTMLTag_listitem, eHTMLTag_newline, //JUST ADDED!
|
|
|
|
eHTMLTag_noframes,
|
|
eHTMLTag_noscript, eHTMLTag_object, eHTMLTag_paragraph, eHTMLTag_pre,
|
|
eHTMLTag_quotation, eHTMLTag_strike, eHTMLTag_samp, eHTMLTag_small,
|
|
eHTMLTag_span, eHTMLTag_strong, eHTMLTag_sub, eHTMLTag_sup,
|
|
eHTMLTag_td, eHTMLTag_text,
|
|
|
|
eHTMLTag_th, eHTMLTag_tt, eHTMLTag_u, eHTMLTag_userdefined,
|
|
eHTMLTag_var, eHTMLTag_whitespace, //JUST ADDED!
|
|
0};
|
|
|
|
//This hack code is here because we don't yet know what to do
|
|
//with userdefined tags... XXX Hack
|
|
if(eHTMLTag_userdefined==aChild) // XXX Hack: For now...
|
|
result=PR_TRUE;
|
|
|
|
//handle form elements (this is very much a WIP!!!)
|
|
if(0!=strchr(formElementTags,aChild)){
|
|
return CanContainFormElement(aParent,aChild);
|
|
}
|
|
|
|
switch(aParent) {
|
|
case eHTMLTag_a:
|
|
result=PRBool(0!=strchr(gTagSet2,aChild)); break;
|
|
|
|
case eHTMLTag_acronym:
|
|
result=PRBool(0!=strchr(gTagSet1,aChild)); break;
|
|
|
|
case eHTMLTag_address:
|
|
result=PRBool(0!=strchr(gTagSet2,aChild)); break;
|
|
|
|
case eHTMLTag_applet:
|
|
{
|
|
static char okTags[]={
|
|
eHTMLTag_a, eHTMLTag_acronym, eHTMLTag_applet, eHTMLTag_bold,
|
|
eHTMLTag_basefont,eHTMLTag_bdo, eHTMLTag_big, eHTMLTag_br,
|
|
eHTMLTag_button, eHTMLTag_cite, eHTMLTag_code, eHTMLTag_dfn,
|
|
eHTMLTag_em, eHTMLTag_font, eHTMLTag_italic, eHTMLTag_iframe,
|
|
eHTMLTag_img, eHTMLTag_input, eHTMLTag_kbd, eHTMLTag_label,
|
|
eHTMLTag_map, eHTMLTag_object, eHTMLTag_param, eHTMLTag_quotation,
|
|
eHTMLTag_samp, eHTMLTag_script, eHTMLTag_select, eHTMLTag_small,
|
|
eHTMLTag_span, eHTMLTag_strike, eHTMLTag_strong, eHTMLTag_sub,
|
|
eHTMLTag_sup, eHTMLTag_textarea, eHTMLTag_tt, eHTMLTag_u,
|
|
eHTMLTag_var,0};
|
|
result=PRBool(0!=strchr(okTags,aChild));
|
|
}
|
|
|
|
|
|
case eHTMLTag_area:
|
|
case eHTMLTag_base:
|
|
case eHTMLTag_basefont:
|
|
case eHTMLTag_br:
|
|
break; //singletons can't contain other tags
|
|
|
|
case eHTMLTag_bdo:
|
|
case eHTMLTag_big:
|
|
case eHTMLTag_blink:
|
|
case eHTMLTag_bold:
|
|
result=PRBool(0!=strchr(gTagSet2,aChild)); break;
|
|
|
|
case eHTMLTag_blockquote:
|
|
case eHTMLTag_body:
|
|
if(eHTMLTag_userdefined==aChild)
|
|
result=PR_TRUE;
|
|
else result=PRBool(0!=strchr(gTagSet1,aChild));
|
|
break;
|
|
|
|
case eHTMLTag_button:
|
|
result=PRBool(0!=strchr(gTagSet3,aChild)); break;
|
|
|
|
case eHTMLTag_caption:
|
|
result=PRBool(0!=strchr(gTagSet2,aChild)); break;
|
|
|
|
case eHTMLTag_center:
|
|
result=PRBool(0!=strchr(gTagSet1,aChild)); break;
|
|
|
|
case eHTMLTag_cite: case eHTMLTag_code:
|
|
result=PRBool(0!=strchr(gTagSet2,aChild)); break;
|
|
|
|
case eHTMLTag_col:
|
|
case eHTMLTag_colgroup:
|
|
break; //singletons can't contain anything...
|
|
|
|
case eHTMLTag_dd:
|
|
result=PRBool(0!=strchr(gTagSet1,aChild)); break;
|
|
|
|
case eHTMLTag_del: case eHTMLTag_dfn:
|
|
result=PRBool(0!=strchr(gTagSet2,aChild)); break;
|
|
|
|
case eHTMLTag_div:
|
|
result=PRBool(0!=strchr(gTagSet1,aChild)); break;
|
|
|
|
case eHTMLTag_dl:
|
|
{
|
|
char okTags[]={eHTMLTag_dd,eHTMLTag_dt,0};
|
|
result=PRBool(0!=strchr(okTags,aChild));
|
|
}
|
|
break;
|
|
|
|
case eHTMLTag_dt:
|
|
break; //singletons can't contain anything...
|
|
|
|
case eHTMLTag_em:
|
|
result=PRBool(0!=strchr(gTagSet2,aChild)); break;
|
|
|
|
case eHTMLTag_fieldset:
|
|
if(eHTMLTag_legend==aChild)
|
|
result=PR_TRUE;
|
|
else result=PRBool(0!=strchr(gTagSet1,aChild));
|
|
break;
|
|
|
|
case eHTMLTag_font:
|
|
result=PRBool(0!=strchr(gTagSet2,aChild)); break;
|
|
|
|
case eHTMLTag_form:
|
|
result=PRBool(0!=strchr(gTagSet1,aChild)); break;
|
|
|
|
case eHTMLTag_frame:
|
|
break; //singletons can't contain other tags
|
|
|
|
case eHTMLTag_frameset:
|
|
{
|
|
static char okTags[]={eHTMLTag_frame,eHTMLTag_frameset,eHTMLTag_noframes,0};
|
|
result=PRBool(0!=strchr(okTags,aChild));
|
|
}
|
|
|
|
case eHTMLTag_h1: case eHTMLTag_h2:
|
|
case eHTMLTag_h3: case eHTMLTag_h4:
|
|
case eHTMLTag_h5: case eHTMLTag_h6:
|
|
{
|
|
if(0!=strchr(gHeadingTags,aChild))
|
|
result=PR_FALSE;
|
|
else result=PRBool(0!=strchr(gTagSet1,aChild));
|
|
}
|
|
break;
|
|
|
|
case eHTMLTag_head:
|
|
{
|
|
static char okTags[]={
|
|
eHTMLTag_base, eHTMLTag_isindex, eHTMLTag_link, eHTMLTag_meta,
|
|
eHTMLTag_script,eHTMLTag_style, eHTMLTag_title, 0};
|
|
result=PRBool(0!=strchr(okTags,aChild));
|
|
}
|
|
break;
|
|
|
|
case eHTMLTag_hr:
|
|
break; //singletons can't contain anything...
|
|
|
|
case eHTMLTag_html:
|
|
{
|
|
static char okTags[]={eHTMLTag_body,eHTMLTag_frameset,eHTMLTag_head,0};
|
|
result=PRBool(0!=strchr(okTags,aChild));
|
|
}
|
|
break;
|
|
|
|
case eHTMLTag_iframe:
|
|
result=PRBool(0!=strchr(gTagSet1,aChild)); break;
|
|
|
|
case eHTMLTag_img:
|
|
case eHTMLTag_input:
|
|
case eHTMLTag_isindex:
|
|
case eHTMLTag_spacer:
|
|
case eHTMLTag_wbr:
|
|
break; //singletons can't contain anything...
|
|
|
|
case eHTMLTag_italic:
|
|
case eHTMLTag_ins:
|
|
case eHTMLTag_kbd:
|
|
case eHTMLTag_label:
|
|
case eHTMLTag_legend:
|
|
result=PRBool(0!=strchr(gTagSet2,aChild)); break;
|
|
|
|
case eHTMLTag_layer:
|
|
break;
|
|
|
|
case eHTMLTag_link:
|
|
break; //singletons can't contain anything...
|
|
|
|
case eHTMLTag_listitem:
|
|
if (eHTMLTag_listitem == aChild) {
|
|
return PR_FALSE;
|
|
}
|
|
result = PR_TRUE;
|
|
break;
|
|
|
|
case eHTMLTag_listing:
|
|
result = PR_TRUE; break;
|
|
|
|
case eHTMLTag_map:
|
|
result=PRBool(eHTMLTag_area==aChild); break;
|
|
|
|
case eHTMLTag_marquee:
|
|
result=PRBool(0!=strchr(gTagSet2,aChild)); break;
|
|
|
|
case eHTMLTag_math:
|
|
break; //nothing but plain text...
|
|
|
|
case eHTMLTag_meta:
|
|
break; //singletons can't contain other tags
|
|
|
|
case eHTMLTag_menu:
|
|
case eHTMLTag_dir:
|
|
case eHTMLTag_ol:
|
|
case eHTMLTag_ul:
|
|
// XXX kipp was here
|
|
result = PR_TRUE;
|
|
break;
|
|
|
|
case eHTMLTag_noframes:
|
|
if(eHTMLTag_body==aChild)
|
|
result=PR_TRUE;
|
|
else result=PRBool(0!=strchr(gTagSet1,aChild));
|
|
break;
|
|
|
|
case eHTMLTag_noscript:
|
|
result=PRBool(0!=strchr(gTagSet1,aChild)); break;
|
|
|
|
case eHTMLTag_note:
|
|
|
|
case eHTMLTag_object:
|
|
result=PRBool(0!=strchr(gTagSet2,aChild)); break;
|
|
|
|
case eHTMLTag_option:
|
|
result=PR_TRUE; break; //for now, allow select to contain anything...
|
|
|
|
case eHTMLTag_paragraph:
|
|
if(eHTMLTag_paragraph==aChild)
|
|
result=PR_FALSE;
|
|
else result=PRBool(0!=strchr(gTagSet2,aChild));
|
|
break;
|
|
|
|
case eHTMLTag_param:
|
|
break; //singletons can't contain other tags
|
|
|
|
case eHTMLTag_plaintext:
|
|
break;
|
|
|
|
case eHTMLTag_pre:
|
|
case eHTMLTag_quotation:
|
|
result=PRBool(0!=strchr(gTagSet2,aChild)); break;
|
|
|
|
case eHTMLTag_strike:
|
|
result=PRBool(0!=strchr(gTagSet2,aChild)); break;
|
|
|
|
case eHTMLTag_script:
|
|
break; //unadorned script text...
|
|
|
|
case eHTMLTag_select:
|
|
result=PR_TRUE; break; //for now, allow select to contain anything...
|
|
|
|
case eHTMLTag_small:
|
|
result=PRBool(0!=strchr(gTagSet2,aChild)); break;
|
|
|
|
case eHTMLTag_span:
|
|
result=PRBool(0!=strchr(gTagSet1,aChild)); break;
|
|
|
|
case eHTMLTag_style:
|
|
break; //singletons can't contain other tags
|
|
|
|
case eHTMLTag_strong:
|
|
case eHTMLTag_samp:
|
|
case eHTMLTag_sub:
|
|
case eHTMLTag_sup:
|
|
result=PRBool(0!=strchr(gTagSet1,aChild)); break;
|
|
|
|
case eHTMLTag_table:
|
|
{
|
|
static char okTags[]={
|
|
eHTMLTag_caption, eHTMLTag_col, eHTMLTag_colgroup,eHTMLTag_tbody,
|
|
eHTMLTag_tfoot, eHTMLTag_tr, eHTMLTag_thead, 0};
|
|
result=PRBool(0!=strchr(okTags,aChild));
|
|
}
|
|
break;
|
|
|
|
case eHTMLTag_tbody:
|
|
case eHTMLTag_tfoot:
|
|
case eHTMLTag_thead:
|
|
result=PRBool(eHTMLTag_tr==aChild); break;
|
|
|
|
case eHTMLTag_th:
|
|
result=PRBool(0!=strchr(gTagSet1,aChild));
|
|
break;
|
|
|
|
case eHTMLTag_td:
|
|
{
|
|
static char extraTags[]={eHTMLTag_newline,0};
|
|
result=PRBool(0!=strchr(extraTags,aChild));
|
|
if(PR_FALSE==result)
|
|
result=PRBool(0!=strchr(gTagSet1,aChild));
|
|
}
|
|
break;
|
|
|
|
case eHTMLTag_textarea:
|
|
case eHTMLTag_title:
|
|
break; //nothing but plain text...
|
|
|
|
case eHTMLTag_tr:
|
|
{
|
|
static char okTags[]={eHTMLTag_td,eHTMLTag_th,0};
|
|
result=PRBool(0!=strchr(okTags,aChild));
|
|
}
|
|
break;
|
|
|
|
case eHTMLTag_tt:
|
|
case eHTMLTag_u:
|
|
result=PRBool(0!=strchr(gTagSet2,aChild)); break;
|
|
|
|
case eHTMLTag_var:
|
|
result=PRBool(0!=strchr(gTagSet2,aChild)); break;
|
|
|
|
case eHTMLTag_userdefined:
|
|
result=PR_TRUE; break; //XXX for now...
|
|
|
|
case eHTMLTag_xmp:
|
|
default:
|
|
break;
|
|
} //switch
|
|
return result;
|
|
}
|
|
|
|
|
|
/**
|
|
* This method is called to determine whether or not a tag
|
|
* of one type can contain a tag of another type.
|
|
*
|
|
* @update gess 4/8/98
|
|
* @param aParent -- tag enum of parent container
|
|
* @param aChild -- tag enum of child container
|
|
* @return PR_TRUE if parent can contain child
|
|
*/
|
|
PRBool CNavDTD::CanContainIndirect(PRInt32 aParent,PRInt32 aChild) const {
|
|
PRBool result=PR_FALSE;
|
|
|
|
switch(aParent) {
|
|
|
|
case eHTMLTag_html:
|
|
{
|
|
static char okTags[]={
|
|
eHTMLTag_head, eHTMLTag_body,
|
|
eHTMLTag_header, eHTMLTag_footer,0
|
|
};
|
|
result=PRBool(0!=strchr(okTags,aChild));
|
|
}
|
|
|
|
case eHTMLTag_body:
|
|
result=PR_TRUE; break;
|
|
|
|
case eHTMLTag_table:
|
|
{
|
|
static char okTags[]={
|
|
eHTMLTag_caption, eHTMLTag_colgroup,
|
|
eHTMLTag_tbody, eHTMLTag_tfoot,
|
|
eHTMLTag_thead, eHTMLTag_tr,
|
|
eHTMLTag_td, eHTMLTag_th,
|
|
eHTMLTag_col, 0};
|
|
result=PRBool(0!=strchr(okTags,aChild));
|
|
}
|
|
break;
|
|
|
|
result=PR_TRUE; break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* This method gets called to determine whether a given
|
|
* tag can contain newlines. Most do not.
|
|
*
|
|
* @update gess 3/25/98
|
|
* @param aTag -- tag to test for containership
|
|
* @return PR_TRUE if given tag can contain other tags
|
|
*/
|
|
PRBool CNavDTD::CanOmit(PRInt32 aParent,PRInt32 aChild) const {
|
|
PRBool result=PR_FALSE;
|
|
|
|
//begin with some simple (and obvious) cases...
|
|
switch((eHTMLTags)aChild) {
|
|
|
|
case eHTMLTag_userdefined:
|
|
case eHTMLTag_comment:
|
|
result=PR_TRUE;
|
|
break;
|
|
|
|
case eHTMLTag_button: case eHTMLTag_fieldset:
|
|
case eHTMLTag_input: case eHTMLTag_isindex:
|
|
case eHTMLTag_label: case eHTMLTag_legend:
|
|
case eHTMLTag_select: case eHTMLTag_textarea:
|
|
if(PR_FALSE==mParser->HasOpenContainer(eHTMLTag_form))
|
|
result=PR_TRUE;
|
|
break;
|
|
|
|
case eHTMLTag_newline:
|
|
case eHTMLTag_whitespace:
|
|
|
|
switch((eHTMLTags)aParent) {
|
|
case eHTMLTag_html: case eHTMLTag_head:
|
|
case eHTMLTag_title: case eHTMLTag_map:
|
|
case eHTMLTag_tr: case eHTMLTag_table:
|
|
case eHTMLTag_thead: case eHTMLTag_tfoot:
|
|
case eHTMLTag_tbody: case eHTMLTag_col:
|
|
case eHTMLTag_colgroup: case eHTMLTag_unknown:
|
|
result=PR_TRUE;
|
|
default:
|
|
break;
|
|
} //switch
|
|
break;
|
|
|
|
default:
|
|
if(eHTMLTag_unknown==aParent)
|
|
result=PR_FALSE;
|
|
break;
|
|
} //switch
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* This method gets called to determine whether a given
|
|
* ENDtag can be omitted. Admittedly,this is a gross simplification.
|
|
*
|
|
* @update gess 3/25/98
|
|
* @param aTag -- tag to test for containership
|
|
* @return PR_TRUE if given tag can contain other tags
|
|
*/
|
|
PRBool CNavDTD::CanOmitEndTag(PRInt32 aParent,PRInt32 aChild) const {
|
|
PRBool result=PR_FALSE;
|
|
|
|
//begin with some simple (and obvious) cases...
|
|
switch((eHTMLTags)aChild) {
|
|
|
|
case eHTMLTag_userdefined:
|
|
case eHTMLTag_comment:
|
|
result=PR_TRUE;
|
|
break;
|
|
|
|
case eHTMLTag_h1: case eHTMLTag_h2:
|
|
case eHTMLTag_h3: case eHTMLTag_h4:
|
|
case eHTMLTag_h5: case eHTMLTag_h6:
|
|
{
|
|
if(0!=strchr(gHeadingTags,aParent))
|
|
result=PR_FALSE;
|
|
//Actually, we probably need to walk the stack here...
|
|
else result=PR_TRUE;
|
|
}
|
|
break;
|
|
|
|
case eHTMLTag_select: case eHTMLTag_option:
|
|
case eHTMLTag_button: case eHTMLTag_fieldset:
|
|
case eHTMLTag_input: case eHTMLTag_isindex:
|
|
case eHTMLTag_label: case eHTMLTag_legend:
|
|
case eHTMLTag_textarea:
|
|
if(PR_FALSE==mParser->HasOpenContainer(aChild))
|
|
result=PR_TRUE;
|
|
break;
|
|
|
|
case eHTMLTag_newline:
|
|
case eHTMLTag_whitespace:
|
|
|
|
switch((eHTMLTags)aParent) {
|
|
case eHTMLTag_html: case eHTMLTag_head:
|
|
case eHTMLTag_title: case eHTMLTag_map:
|
|
case eHTMLTag_tr: case eHTMLTag_table:
|
|
case eHTMLTag_thead: case eHTMLTag_tfoot:
|
|
case eHTMLTag_tbody: case eHTMLTag_col:
|
|
case eHTMLTag_colgroup: case eHTMLTag_unknown:
|
|
result=PR_TRUE;
|
|
default:
|
|
break;
|
|
} //switch
|
|
break;
|
|
|
|
default:
|
|
result=(!mParser->HasOpenContainer(aChild));
|
|
break;
|
|
} //switch
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* This method gets called to determine whether a given
|
|
* tag is itself a container
|
|
*
|
|
* @update gess 4/8/98
|
|
* @param aTag -- tag to test for containership
|
|
* @return PR_TRUE if given tag can contain other tags
|
|
*/
|
|
PRBool CNavDTD::IsContainer(PRInt32 aTag) const {
|
|
PRBool result=PR_FALSE;
|
|
|
|
switch(aTag){
|
|
case eHTMLTag_area: case eHTMLTag_base:
|
|
case eHTMLTag_basefont: case eHTMLTag_br:
|
|
case eHTMLTag_col: case eHTMLTag_colgroup:
|
|
case eHTMLTag_frame:
|
|
case eHTMLTag_hr: case eHTMLTag_img:
|
|
case eHTMLTag_input: case eHTMLTag_isindex:
|
|
case eHTMLTag_link:
|
|
case eHTMLTag_math: case eHTMLTag_meta:
|
|
// case eHTMLTag_option:
|
|
case eHTMLTag_param:
|
|
case eHTMLTag_style: case eHTMLTag_spacer:
|
|
case eHTMLTag_wbr:
|
|
case eHTMLTag_form:
|
|
case eHTMLTag_newline:
|
|
case eHTMLTag_whitespace:
|
|
case eHTMLTag_text:
|
|
result=PR_FALSE;
|
|
break;
|
|
|
|
default:
|
|
result=PR_TRUE;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* This method does two things: 1st, help construct
|
|
* our own internal model of the content-stack; and
|
|
* 2nd, pass this message on to the sink.
|
|
* @update gess4/6/98
|
|
* @param aNode -- next node to be added to model
|
|
* @return TRUE if ok, FALSE if error
|
|
*/
|
|
PRInt32 CNavDTD::GetDefaultParentTagFor(PRInt32 aTag) const{
|
|
eHTMLTags result=eHTMLTag_unknown;
|
|
switch(aTag) {
|
|
|
|
case eHTMLTag_text:
|
|
result=eHTMLTag_paragraph; break;
|
|
|
|
case eHTMLTag_html:
|
|
result=eHTMLTag_unknown; break;
|
|
|
|
case eHTMLTag_body:
|
|
case eHTMLTag_head:
|
|
case eHTMLTag_header:
|
|
case eHTMLTag_footer:
|
|
case eHTMLTag_frameset:
|
|
result=eHTMLTag_html; break;
|
|
|
|
//These tags are head specific...
|
|
case eHTMLTag_style:
|
|
case eHTMLTag_meta:
|
|
case eHTMLTag_title:
|
|
case eHTMLTag_base:
|
|
case eHTMLTag_link:
|
|
result=eHTMLTag_head; break;
|
|
|
|
//These tags are table specific...
|
|
case eHTMLTag_caption:
|
|
case eHTMLTag_colgroup:
|
|
case eHTMLTag_tbody:
|
|
case eHTMLTag_tfoot:
|
|
case eHTMLTag_thead:
|
|
result=eHTMLTag_table; break;
|
|
|
|
case eHTMLTag_tr:
|
|
result=eHTMLTag_tbody; break;
|
|
|
|
case eHTMLTag_td:
|
|
case eHTMLTag_th:
|
|
result=eHTMLTag_tr; break;
|
|
|
|
case eHTMLTag_col:
|
|
result=eHTMLTag_colgroup; break;
|
|
|
|
//These have to do with listings...
|
|
case eHTMLTag_listitem:
|
|
result=eHTMLTag_ul; break;
|
|
|
|
case eHTMLTag_dd:
|
|
case eHTMLTag_dt:
|
|
result=eHTMLTag_dl; break;
|
|
|
|
case eHTMLTag_option:
|
|
result=eHTMLTag_select; break;
|
|
|
|
//These have to do with image maps...
|
|
case eHTMLTag_area:
|
|
result=eHTMLTag_map; break;
|
|
|
|
//These have to do with applets...
|
|
case eHTMLTag_param:
|
|
result=eHTMLTag_applet; break;
|
|
|
|
//These have to do with frames...
|
|
case eHTMLTag_frame:
|
|
result=eHTMLTag_frameset; break;
|
|
|
|
default:
|
|
result=eHTMLTag_body; //XXX Hack! Just for now.
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
/**
|
|
* This method gets called at various times by the parser
|
|
* whenever we want to verify a valid context stack. This
|
|
* method also gives us a hook to add debugging metrics.
|
|
*
|
|
* @update gess4/6/98
|
|
* @param aStack[] array of ints (tokens)
|
|
* @param aCount number of elements in given array
|
|
* @return TRUE if stack is valid, else FALSE
|
|
*/
|
|
PRBool CNavDTD::VerifyContextVector(PRInt32* aVector,PRInt32 aCount) const {
|
|
PRBool result=PR_TRUE;
|
|
|
|
if(aCount>0) {
|
|
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
/**
|
|
* This method tries to design a context vector (without actually
|
|
* changing our parser state) from the parent down to the
|
|
* child.
|
|
*
|
|
* @update gess4/6/98
|
|
* @param aVector is the string where we store our output vector
|
|
* in bottom-up order.
|
|
* @param aParent -- tag type of parent
|
|
* @param aChild -- tag type of child
|
|
* @return TRUE if propagation closes; false otherwise
|
|
*/
|
|
PRBool CNavDTD::ForwardPropagate(nsString& aVector,PRInt32 aParentTag,PRInt32 aChildTag) const {
|
|
PRBool result=PR_FALSE;
|
|
|
|
switch(aParentTag) {
|
|
case eHTMLTag_table:
|
|
case eHTMLTag_tr:
|
|
if(PR_TRUE==CanContain(eHTMLTag_td,aChildTag)) {
|
|
aVector.Append((PRUnichar)eHTMLTag_td);
|
|
result=BackwardPropagate(aVector,aParentTag,eHTMLTag_td);
|
|
// result=PR_TRUE;
|
|
}
|
|
|
|
break;
|
|
|
|
case eHTMLTag_th:
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}//switch
|
|
return result;
|
|
}
|
|
|
|
|
|
/**
|
|
* This method tries to design a context map (without actually
|
|
* changing our parser state) from the child up to the parent.
|
|
*
|
|
* @update gess4/6/98
|
|
* @param aVector is the string where we store our output vector
|
|
* in bottom-up order.
|
|
* @param aParent -- tag type of parent
|
|
* @param aChild -- tag type of child
|
|
* @return TRUE if propagation closes; false otherwise
|
|
*/
|
|
PRBool CNavDTD::BackwardPropagate(nsString& aVector,PRInt32 aParentTag,PRInt32 aChildTag) const {
|
|
|
|
PRBool result=PR_FALSE;
|
|
eHTMLTags theParentTag=(eHTMLTags)aChildTag;
|
|
|
|
// aVector.Truncate();
|
|
|
|
//create the necessary stack of parent tags...
|
|
//continue your search until you run out of known parents,
|
|
//or you find the specific parent you were given (aParentTag).
|
|
// aVector.Append((PRUnichar)aChildTag);
|
|
do {
|
|
theParentTag=(eHTMLTags)GetDefaultParentTagFor(theParentTag);
|
|
if(theParentTag!=eHTMLTag_unknown) {
|
|
aVector.Append((PRUnichar)theParentTag);
|
|
}
|
|
} while((theParentTag!=eHTMLTag_unknown) && (theParentTag!=aParentTag));
|
|
|
|
return PRBool(aParentTag==theParentTag);
|
|
}
|
|
|
|
|
|
|