author | Blake Kaplan <mrbkap@gmail.com> |
Mon, 12 Aug 2013 11:28:41 -0400 | |
changeset 142331 | 0bcfd14b61e81ef3bb389e9196109b7ba6b6b534 |
parent 142330 | 8c2d7f586811baf315b0685b30311e00f3a1765a |
child 142332 | f64b25b245022165eb5cc122560200ce3a2a5b53 |
push id | 25093 |
push user | cbook@mozilla.com |
push date | Tue, 13 Aug 2013 10:34:53 +0000 |
treeherder | mozilla-central@a0e613b4f4d8 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | hsivonen |
bugs | 903912 |
milestone | 26.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/content/html/document/src/nsHTMLContentSink.cpp +++ b/content/html/document/src/nsHTMLContentSink.cpp @@ -20,17 +20,17 @@ #include "nsIInterfaceRequestor.h" #include "nsIInterfaceRequestorUtils.h" #include "nsScriptLoader.h" #include "nsIURI.h" #include "nsNetUtil.h" #include "nsIContentViewer.h" #include "nsIMarkupDocumentViewer.h" #include "nsINodeInfo.h" -#include "nsHTMLTokens.h" +#include "nsToken.h" #include "nsIAppShell.h" #include "nsCRT.h" #include "prtime.h" #include "prlog.h" #include "nsNodeUtils.h" #include "nsIContent.h" #include "mozilla/dom/Element.h" #include "mozilla/Preferences.h" @@ -425,24 +425,18 @@ HTMLContentSink::AddAttributes(const nsI already_AddRefed<nsGenericHTMLElement> HTMLContentSink::CreateContentObject(const nsIParserNode& aNode, nsHTMLTag aNodeType) { // Find/create atom for the tag name nsCOMPtr<nsINodeInfo> nodeInfo; - if (aNodeType == eHTMLTag_userdefined) { - nsAutoString lower; - nsContentUtils::ASCIIToLower(aNode.GetText(), lower); - nsCOMPtr<nsIAtom> name = do_GetAtom(lower); - nodeInfo = mNodeInfoManager->GetNodeInfo(name, nullptr, kNameSpaceID_XHTML, - nsIDOMNode::ELEMENT_NODE); - } - else if (mNodeInfoCache[aNodeType]) { + MOZ_ASSERT(aNodeType != eHTMLTag_userdefined); + if (mNodeInfoCache[aNodeType]) { nodeInfo = mNodeInfoCache[aNodeType]; } else { nsIParserService *parserService = nsContentUtils::GetParserService(); if (!parserService) return nullptr; nsIAtom *name = parserService->HTMLIdToAtomTag(aNodeType); @@ -859,35 +853,21 @@ SinkContext::AddLeaf(const nsIParserNode break; } } break; case eToken_text: case eToken_whitespace: case eToken_newline: - rv = AddText(aNode.GetText()); + MOZ_CRASH(); break; case eToken_entity: - { - nsAutoString tmp; - int32_t unicode = aNode.TranslateToUnicodeStr(tmp); - if (unicode < 0) { - rv = AddText(aNode.GetText()); - } else { - // Map carriage returns to newlines - if (!tmp.IsEmpty()) { - if (tmp.CharAt(0) == '\r') { - tmp.Assign((PRUnichar)'\n'); - } - rv = AddText(tmp); - } - } - } + MOZ_CRASH(); break; default: break; } return rv; }
--- a/content/xbl/src/nsXBLContentSink.cpp +++ b/content/xbl/src/nsXBLContentSink.cpp @@ -6,17 +6,16 @@ #include "mozilla/Util.h" #include "nsXBLContentSink.h" #include "nsIDocument.h" #include "nsBindingManager.h" #include "nsIDOMNode.h" #include "nsGkAtoms.h" #include "nsINameSpaceManager.h" -#include "nsHTMLTokens.h" #include "nsIURI.h" #include "nsTextFragment.h" #ifdef MOZ_XUL #include "nsXULElement.h" #endif #include "nsXBLProtoImplProperty.h" #include "nsXBLProtoImplMethod.h" #include "nsXBLProtoImplField.h"
--- a/parser/htmlparser/public/moz.build +++ b/parser/htmlparser/public/moz.build @@ -9,17 +9,16 @@ XPIDL_SOURCES += [ 'nsIExtendedExpatSink.idl', ] MODULE = 'htmlparser' EXPORTS += [ 'nsHTMLTagList.h', 'nsHTMLTags.h', - 'nsHTMLTokens.h', 'nsIContentSink.h', 'nsIDTD.h', 'nsIElementObserver.h', 'nsIFragmentContentSink.h', 'nsIHTMLContentSink.h', 'nsIParser.h', 'nsIParserNode.h', 'nsIParserService.h',
deleted file mode 100644 --- a/parser/htmlparser/public/nsHTMLTokens.h +++ /dev/null @@ -1,376 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * MODULE NOTES: - * @update gess 4/1/98 - * - * This file contains the declarations for all the HTML specific token types that - * our DTD's understand. In fact, the same set of token types are used for XML. - * Currently we have tokens for text, comments, start and end tags, entities, - * attributes, style, script and skipped content. Whitespace and newlines also - * have their own token types, but don't count on them to stay forever. - * - * If you're looking for the html tags, they're in a file called nsHTMLTag.h/cpp. - * - * Most of the token types have a similar API. They have methods to get the type - * of token (GetTokenType); those that represent HTML tags also have a method to - * get type tag type (GetTypeID). In addition, most have a method that causes the - * token to help in the parsing process called (Consume). We've also thrown in a - * few standard debugging methods as well. - */ - -#ifndef HTMLTOKENS_H -#define HTMLTOKENS_H - -#include "nsToken.h" -#include "nsHTMLTags.h" -#include "nsString.h" -#include "nsScannerString.h" - -class nsScanner; - - /******************************************************************* - * This enum defines the set of token types that we currently support. - *******************************************************************/ - -enum eHTMLTokenTypes { - eToken_unknown=0, - eToken_start=1, eToken_end, eToken_comment, eToken_entity, - eToken_whitespace, eToken_newline, eToken_text, eToken_attribute, - eToken_instruction, eToken_cdatasection, eToken_doctypeDecl, eToken_markupDecl, - eToken_last //make sure this stays the last token... -}; - -nsresult ConsumeQuotedString(PRUnichar aChar,nsString& aString,nsScanner& aScanner); -nsresult ConsumeAttributeText(PRUnichar aChar,nsString& aString,nsScanner& aScanner); -const PRUnichar* GetTagName(int32_t aTag); -//int32_t FindEntityIndex(nsString& aString,int32_t aCount=-1); - - - -/** - * This declares the basic token type used in the HTML DTD's. - * @update gess 3/25/98 - */ -class CHTMLToken : public CToken { -public: - virtual ~CHTMLToken(); - CHTMLToken(eHTMLTags aTag); - - virtual eContainerInfo GetContainerInfo(void) const {return eFormUnknown;} - virtual void SetContainerInfo(eContainerInfo aInfo) { } - -protected: -}; - -/** - * This declares start tokens, which always take the form <xxxx>. - * This class also knows how to consume related attributes. - * - * @update gess 3/25/98 - */ -class CStartToken: public CHTMLToken { -public: - CStartToken(eHTMLTags aTag=eHTMLTag_unknown); - CStartToken(const nsAString& aString); - CStartToken(const nsAString& aName,eHTMLTags aTag); - - virtual nsresult Consume(PRUnichar aChar,nsScanner& aScanner,int32_t aMode); - virtual int32_t GetTypeID(void); - virtual int32_t GetTokenType(void); - - virtual bool IsEmpty(void); - virtual void SetEmpty(bool aValue); - - virtual const nsSubstring& GetStringValue(); - virtual void GetSource(nsString& anOutputString); - virtual void AppendSourceTo(nsAString& anOutputString); - - // the following info is used to set well-formedness state on start tags... - virtual eContainerInfo GetContainerInfo(void) const {return mContainerInfo;} - virtual void SetContainerInfo(eContainerInfo aContainerInfo) { - if (eFormUnknown==mContainerInfo) { - mContainerInfo=aContainerInfo; - } - } - virtual bool IsWellFormed(void) const { - return eWellFormed == mContainerInfo; - } - - nsString mTextValue; -protected: - eContainerInfo mContainerInfo; - bool mEmpty; -#ifdef DEBUG - bool mAttributed; -#endif -}; - - -/** - * This declares end tokens, which always take the - * form </xxxx>. This class also knows how to consume - * related attributes. - * - * @update gess 3/25/98 - */ -class CEndToken: public CHTMLToken { -public: - CEndToken(eHTMLTags aTag); - CEndToken(const nsAString& aString); - CEndToken(const nsAString& aName,eHTMLTags aTag); - virtual nsresult Consume(PRUnichar aChar,nsScanner& aScanner,int32_t aMode); - virtual int32_t GetTypeID(void); - virtual int32_t GetTokenType(void); - - virtual const nsSubstring& GetStringValue(); - virtual void GetSource(nsString& anOutputString); - virtual void AppendSourceTo(nsAString& anOutputString); - -protected: - nsString mTextValue; -}; - - -/** - * This declares comment tokens. Comments are usually - * thought of as tokens, but we treat them that way - * here so that the parser can have a consistent view - * of all tokens. - * - * @update gess 3/25/98 - */ -class CCommentToken: public CHTMLToken { -public: - CCommentToken(); - CCommentToken(const nsAString& aString); - virtual nsresult Consume(PRUnichar aChar,nsScanner& aScanner,int32_t aMode); - virtual int32_t GetTokenType(void); - virtual const nsSubstring& GetStringValue(void); - virtual void AppendSourceTo(nsAString& anOutputString); - - nsresult ConsumeStrictComment(nsScanner& aScanner); - nsresult ConsumeQuirksComment(nsScanner& aScanner); - -protected: - nsScannerSubstring mComment; // does not include MDO & MDC - nsScannerSubstring mCommentDecl; // includes MDO & MDC -}; - - -/** - * This class declares entity tokens, which always take - * the form &xxxx;. This class also offers a few utility - * methods that allow you to easily reduce entities. - * - * @update gess 3/25/98 - */ -class CEntityToken : public CHTMLToken { -public: - CEntityToken(); - CEntityToken(const nsAString& aString); - virtual int32_t GetTokenType(void); - int32_t TranslateToUnicodeStr(nsString& aString); - virtual nsresult Consume(PRUnichar aChar,nsScanner& aScanner,int32_t aMode); - static nsresult ConsumeEntity(PRUnichar aChar, nsString& aString, - nsScanner& aScanner); - static int32_t TranslateToUnicodeStr(int32_t aValue,nsString& aString); - - virtual const nsSubstring& GetStringValue(void); - virtual void GetSource(nsString& anOutputString); - virtual void AppendSourceTo(nsAString& anOutputString); - -protected: - nsString mTextValue; -}; - - -/** - * Whitespace tokens are used where whitespace can be - * detected as distinct from text. This allows us to - * easily skip leading/trailing whitespace when desired. - * - * @update gess 3/25/98 - */ -class CWhitespaceToken: public CHTMLToken { -public: - CWhitespaceToken(); - CWhitespaceToken(const nsAString& aString); - virtual nsresult Consume(PRUnichar aChar,nsScanner& aScanner,int32_t aMode); - virtual int32_t GetTokenType(void); - virtual const nsSubstring& GetStringValue(void); - -protected: - nsScannerSharedSubstring mTextValue; -}; - -/** - * Text tokens contain the normalized form of html text. - * These tokens are guaranteed not to contain entities, - * start or end tags, or newlines. - * - * @update gess 3/25/98 - */ -class CTextToken: public CHTMLToken { -public: - CTextToken(); - CTextToken(const nsAString& aString); - virtual nsresult Consume(PRUnichar aChar,nsScanner& aScanner,int32_t aMode); - virtual int32_t GetTokenType(void); - virtual int32_t GetTextLength(void); - virtual void CopyTo(nsAString& aStr); - virtual const nsSubstring& GetStringValue(void); - virtual void Bind(nsScanner* aScanner, nsScannerIterator& aStart, - nsScannerIterator& aEnd); - virtual void Bind(const nsAString& aStr); - - nsresult ConsumeCharacterData(bool aIgnoreComments, - nsScanner& aScanner, - const nsAString& aEndTagName, - int32_t aFlag, - bool& aFlushTokens); - - nsresult ConsumeParsedCharacterData(bool aDiscardFirstNewline, - bool aConservativeConsume, - nsScanner& aScanner, - const nsAString& aEndTagName, - int32_t aFlag, - bool& aFound); - -protected: - nsScannerSubstring mTextValue; -}; - - -/** - * CDATASection tokens contain raw unescaped text content delimited by - * a ![CDATA[ and ]]. - * XXX Not really a HTML construct - maybe we need a separation - * - * @update vidur 11/12/98 - */ -class CCDATASectionToken : public CHTMLToken { -public: - CCDATASectionToken(eHTMLTags aTag = eHTMLTag_unknown); - CCDATASectionToken(const nsAString& aString); - virtual nsresult Consume(PRUnichar aChar,nsScanner& aScanner,int32_t aMode); - virtual int32_t GetTokenType(void); - virtual const nsSubstring& GetStringValue(void); - -protected: - nsString mTextValue; -}; - - -/** - * Declaration tokens contain raw unescaped text content (not really, but - * right now we use this only for view source). - * XXX Not really a HTML construct - maybe we need a separation - * - */ -class CMarkupDeclToken : public CHTMLToken { -public: - CMarkupDeclToken(); - CMarkupDeclToken(const nsAString& aString); - virtual nsresult Consume(PRUnichar aChar,nsScanner& aScanner,int32_t aMode); - virtual int32_t GetTokenType(void); - virtual const nsSubstring& GetStringValue(void); - -protected: - nsScannerSubstring mTextValue; -}; - - -/** - * Attribute tokens are used to contain attribute key/value - * pairs whereever they may occur. Typically, they should - * occur only in start tokens. However, we may expand that - * ability when XML tokens become commonplace. - * - * @update gess 3/25/98 - */ -class CAttributeToken: public CHTMLToken { -public: - CAttributeToken(); - CAttributeToken(const nsAString& aString); - CAttributeToken(const nsAString& aKey, const nsAString& aString); - ~CAttributeToken() {} - virtual nsresult Consume(PRUnichar aChar,nsScanner& aScanner,int32_t aMode); - virtual int32_t GetTokenType(void); - const nsSubstring& GetKey(void) { return mTextKey.AsString(); } - virtual void SetKey(const nsAString& aKey); - virtual void BindKey(nsScanner* aScanner, nsScannerIterator& aStart, - nsScannerIterator& aEnd); - const nsSubstring& GetValue(void) {return mTextValue.str();} - virtual const nsSubstring& GetStringValue(void); - virtual void GetSource(nsString& anOutputString); - virtual void AppendSourceTo(nsAString& anOutputString); - - bool mHasEqualWithoutValue; -protected: - nsScannerSharedSubstring mTextValue; - nsScannerSubstring mTextKey; -}; - - -/** - * Newline tokens contain, you guessed it, newlines. - * They consume newline (CR/LF) either alone or in pairs. - * - * @update gess 3/25/98 - */ -class CNewlineToken: public CHTMLToken { -public: - CNewlineToken(); - virtual nsresult Consume(PRUnichar aChar,nsScanner& aScanner,int32_t aMode); - virtual int32_t GetTokenType(void); - virtual const nsSubstring& GetStringValue(void); - - static void AllocNewline(); - static void FreeNewline(); -}; - - -/** - * Whitespace tokens are used where whitespace can be - * detected as distinct from text. This allows us to - * easily skip leading/trailing whitespace when desired. - * - * @update gess 3/25/98 - */ -class CInstructionToken: public CHTMLToken { -public: - CInstructionToken(); - CInstructionToken(const nsAString& aString); - virtual nsresult Consume(PRUnichar aChar,nsScanner& aScanner,int32_t aMode); - virtual int32_t GetTokenType(void); - virtual const nsSubstring& GetStringValue(void); - -protected: - nsString mTextValue; -}; - - -/** - * This token is generated by the HTML and Expat tokenizers - * when they see the doctype declaration ("<!DOCTYPE ... >") - * - */ - -class CDoctypeDeclToken: public CHTMLToken { -public: - CDoctypeDeclToken(eHTMLTags aTag=eHTMLTag_unknown); - CDoctypeDeclToken(const nsAString& aString,eHTMLTags aTag=eHTMLTag_unknown); - virtual nsresult Consume(PRUnichar aChar,nsScanner& aScanner,int32_t aMode); - virtual int32_t GetTokenType(void); - virtual const nsSubstring& GetStringValue(void); - virtual void SetStringValue(const nsAString& aStr); - -protected: - nsString mTextValue; -}; - -#endif
--- a/parser/htmlparser/public/nsIDTD.h +++ b/parser/htmlparser/public/nsIDTD.h @@ -42,17 +42,16 @@ enum nsDTDMode { eDTDMode_almost_standards, eDTDMode_full_standards, eDTDMode_autodetect, eDTDMode_fragment }; class nsIParser; -class CToken; class nsIURI; class nsIContentSink; class CParserContext; class nsIDTD : public nsISupports { public: @@ -76,19 +75,17 @@ public: * * @param aTokenizer - tokenizer providing the token stream to be parsed * @param aCountLines - informs the DTD whether to count newlines * (not wanted, e.g., when handling document.write) * @param aCharsetPtr - address of an nsCString containing the charset * that the DTD should use (pointer in case the DTD * opts to ignore this parameter) */ - NS_IMETHOD BuildModel(nsITokenizer* aTokenizer, - bool aCountLines, - const nsCString* aCharsetPtr) = 0; + NS_IMETHOD BuildModel(nsITokenizer* aTokenizer, nsIContentSink* aSink) = 0; /** * This method is called to determine whether or not a tag of one * type can contain a tag of another type. * * @update gess 3/25/98 * @param aParent -- int tag of parent container * @param aChild -- int tag of child container @@ -127,15 +124,15 @@ public: NS_IMETHOD_(nsDTDMode) GetMode() const = 0; }; NS_DEFINE_STATIC_IID_ACCESSOR(nsIDTD, NS_IDTD_IID) #define NS_DECL_NSIDTD \ NS_IMETHOD WillBuildModel( const CParserContext& aParserContext, nsITokenizer* aTokenizer, nsIContentSink* aSink);\ NS_IMETHOD DidBuildModel(nsresult anErrorCode);\ - NS_IMETHOD BuildModel(nsITokenizer* aTokenizer, bool aCountLines, const nsCString* aCharsetPtr);\ + NS_IMETHOD BuildModel(nsITokenizer* aTokenizer, nsIContentSink* aSink);\ NS_IMETHOD_(bool) CanContain(int32_t aParent,int32_t aChild) const;\ NS_IMETHOD_(bool) IsContainer(int32_t aTag) const;\ NS_IMETHOD_(void) Terminate();\ NS_IMETHOD_(int32_t) GetType();\ NS_IMETHOD_(nsDTDMode) GetMode() const; #endif /* nsIDTD_h___ */
--- a/parser/htmlparser/public/nsIParserNode.h +++ b/parser/htmlparser/public/nsIParserNode.h @@ -18,58 +18,30 @@ * If you want to hang onto one of these, you should * make your own copy. * */ #ifndef NS_IPARSERNODE__ #define NS_IPARSERNODE__ -#include "nsISupports.h" #include "nsStringGlue.h" -#include "nsDebug.h" - -//#define HEAP_ALLOCATED_NODES -//#define DEBUG_TRACK_NODES class nsIAtom; -class CToken; - -// 6e59f160-2717-11d2-9246-00805f8a7ab6 -#define NS_IPARSER_NODE_IID \ - {0x6e59f160, 0x2717, 0x11d1, \ - {0x92, 0x46, 0x00, 0x80, 0x5f, 0x8a, 0x7a, 0xb6}} /** * Parser nodes are the unit of exchange between the * parser and the content sink. Nodes offer access to * the current token, its attributes, and its skipped- * content if applicable. * * @update gess 3/25/98 */ -class nsIParserNode { // XXX Should be nsAParserNode - +class nsIParserNode { public: - - - /** - * Retrieve the name of the node - * @update gess5/11/98 - * @return string containing node name - */ - virtual const nsAString& GetTagName() const = 0; //to get name of tag - - /** - * Retrieve the text from the given node - * @update gess5/11/98 - * @return string containing node text - */ - virtual const nsAString& GetText() const = 0; //get plain text if available - /** * Retrieve the type of the parser node. * @update gess5/11/98 * @return node type. */ virtual int32_t GetNodeType() const =0; /** @@ -79,68 +51,28 @@ class nsIParserNode { // XXX Should be n */ virtual int32_t GetTokenType() const =0; /** * Retrieve the number of attributes in this node. * @update gess5/11/98 * @return count of attributes (may be 0) */ - virtual int32_t GetAttributeCount(bool askToken=false) const =0; + virtual int32_t GetAttributeCount() const =0; /** * Retrieve the key (of key/value pair) at given index * @update gess5/11/98 * @param anIndex is the index of the key you want * @return string containing key. */ virtual const nsAString& GetKeyAt(uint32_t anIndex) const = 0; /** * Retrieve the value (of key/value pair) at given index * @update gess5/11/98 * @param anIndex is the index of the value you want * @return string containing value. */ virtual const nsAString& GetValueAt(uint32_t anIndex) const = 0; - - /** - * NOTE: When the node is an entity, this will translate the entity - * to it's unicode value, and store it in aString. - * @update gess5/11/98 - * @param aString will contain the resulting unicode string value - * @return int (unicode char or unicode index from table) - */ - virtual int32_t TranslateToUnicodeStr(nsString& aString) const = 0; - - - virtual void AddAttribute(CToken* aToken)=0; - - /** - * This getter retrieves the line number from the input source where - * the token occurred. Lines are interpreted as occurring between \n characters. - * @update gess7/24/98 - * @return int containing the line number the token was found on - */ - virtual int32_t GetSourceLineNumber(void) const =0; - - /** - * This pair of methods allows us to set a generic bit (for arbitrary use) - * on each node stored in the context. - * @update gess 11May2000 - */ - virtual bool GetGenericState(void) const =0; - virtual void SetGenericState(bool aState) =0; - - /** Retrieve a string containing the tag and its attributes in "source" form - * @update rickg 06June2000 - * @return void - */ - virtual void GetSource(nsString& aString) const = 0; - - /** Release all the objects you're holding - * @update harishd 08/02/00 - * @return void - */ - virtual nsresult ReleaseAll()=0; }; #endif
--- a/parser/htmlparser/public/nsITokenizer.h +++ b/parser/htmlparser/public/nsITokenizer.h @@ -10,60 +10,35 @@ * */ #ifndef __NSITOKENIZER__ #define __NSITOKENIZER__ #include "nsISupports.h" -class CToken; class nsScanner; -class nsDeque; -class nsTokenAllocator; #define NS_ITOKENIZER_IID \ - {0xe4238ddc, 0x9eb6, 0x11d2, {0xba, 0xa5, 0x0, 0x10, 0x4b, 0x98, 0x3f, 0xd4 }} - +{ 0Xae98a348, 0X5e91, 0X41a8, \ + { 0Xa5, 0Xb4, 0Xd2, 0X20, 0Xf3, 0X1f, 0Xc4, 0Xab } } /*************************************************************** Notes: ***************************************************************/ class nsITokenizer : public nsISupports { public: NS_DECLARE_STATIC_IID_ACCESSOR(NS_ITOKENIZER_IID) - NS_IMETHOD WillTokenize(bool aIsFinalChunk,nsTokenAllocator* aTokenAllocator)=0; + NS_IMETHOD WillTokenize(bool aIsFinalChunk)=0; NS_IMETHOD ConsumeToken(nsScanner& aScanner,bool& aFlushTokens)=0; - NS_IMETHOD DidTokenize(bool aIsFinalChunk)=0; - - NS_IMETHOD_(CToken*) PushTokenFront(CToken* aToken)=0; - NS_IMETHOD_(CToken*) PushToken(CToken* aToken)=0; - NS_IMETHOD_(CToken*) PopToken(void)=0; - NS_IMETHOD_(CToken*) PeekToken(void)=0; - NS_IMETHOD_(CToken*) GetTokenAt(int32_t anIndex)=0; - NS_IMETHOD_(int32_t) GetCount(void)=0; - NS_IMETHOD_(nsTokenAllocator*) GetTokenAllocator(void)=0; - NS_IMETHOD_(void) PrependTokens(nsDeque& aDeque)=0; - NS_IMETHOD CopyState(nsITokenizer* aTokenizer)=0; - }; NS_DEFINE_STATIC_IID_ACCESSOR(nsITokenizer, NS_ITOKENIZER_IID) #define NS_DECL_NSITOKENIZER \ - NS_IMETHOD WillTokenize(bool aIsFinalChunk,nsTokenAllocator* aTokenAllocator);\ + NS_IMETHOD WillTokenize(bool aIsFinalChunk);\ NS_IMETHOD ConsumeToken(nsScanner& aScanner,bool& aFlushTokens);\ - NS_IMETHOD DidTokenize(bool aIsFinalChunk);\ - NS_IMETHOD_(CToken*) PushTokenFront(CToken* aToken);\ - NS_IMETHOD_(CToken*) PushToken(CToken* aToken);\ - NS_IMETHOD_(CToken*) PopToken(void);\ - NS_IMETHOD_(CToken*) PeekToken(void);\ - NS_IMETHOD_(CToken*) GetTokenAt(int32_t anIndex);\ - NS_IMETHOD_(int32_t) GetCount(void);\ - NS_IMETHOD_(nsTokenAllocator*) GetTokenAllocator(void);\ - NS_IMETHOD_(void) PrependTokens(nsDeque& aDeque);\ - NS_IMETHOD CopyState(nsITokenizer* aTokenizer); #endif
--- a/parser/htmlparser/public/nsToken.h +++ b/parser/htmlparser/public/nsToken.h @@ -1,263 +1,26 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * MODULE NOTES: - * @update gess 4/1/98 - * - * This class is defines the basic notion of a token - * within our system. All other tokens are derived from - * this one. It offers a few basic interfaces, but the - * most important is consume(). The consume() method gets - * called during the tokenization process when an instance - * of that particular token type gets detected in the - * input stream. - * - * CToken objects that are allocated from the heap are allocated - * using the nsTokenAllocator object. nsTokenAllocator used to use - * an arena-style allocator, but that is no longer necessary or helpful; - * it now uses a trivial drop-in replacement for the arena-style - * allocator called nsDummyAllocator, which just wraps malloc/free. - */ - - #ifndef CTOKEN__ #define CTOKEN__ #include "prtypes.h" #include "nsString.h" #include "nsError.h" class nsScanner; class nsTokenAllocator; -/** - * A trivial allocator. See the comment at the top of this file. - */ -class nsDummyAllocator { -public: - void* Alloc(size_t aSize) { return malloc(aSize); } - void Free(void* aPtr) { free(aPtr); } -}; - -enum eContainerInfo { - eWellFormed, - eMalformed, - eFormUnknown +enum eHTMLTokenTypes { + eToken_unknown=0, + eToken_start=1, eToken_end, eToken_comment, eToken_entity, + eToken_whitespace, eToken_newline, eToken_text, eToken_attribute, + eToken_instruction, eToken_cdatasection, eToken_doctypeDecl, eToken_markupDecl, + eToken_last //make sure this stays the last token... }; -/** - * Token objects represent sequences of characters as they - * are consumed from the input stream (URL). While they're - * pretty general in nature, we use subclasses (found in - * nsHTMLTokens.h) to define <start>, </end>, <text>, - * <comment>, <&entity>, <newline>, and <whitespace> tokens. - * - * @update gess 3/25/98 - */ -class CToken { - public: - - enum eTokenOrigin {eSource,eResidualStyle}; - - protected: - - // nsTokenAllocator should be the only class that tries to - // allocate tokens from the heap. - friend class nsTokenAllocator; - - /** - * - * @update harishd 08/01/00 - * @param aSize - - * @param aArena - Allocate memory from this pool. - */ - static void * operator new (size_t aSize, nsDummyAllocator& anArena) CPP_THROW_NEW - { - return anArena.Alloc(aSize); - } - - /** - * Hide operator delete; clients should use Destroy() instead. - */ - static void operator delete (void*,size_t) {} - - protected: - /** - * destructor - * @update gess5/11/98 - */ - virtual ~CToken(); - - private: - /** - * Destroy a token. - */ - static void Destroy(CToken* aToken, nsDummyAllocator& aArenaPool) - { - aToken->~CToken(); - aArenaPool.Free(aToken); - } - - public: - /** - * Make a note on number of times you have been referenced - * @update harishd 08/02/00 - */ - void AddRef() { - ++mUseCount; - NS_LOG_ADDREF(this, mUseCount, "CToken", sizeof(*this)); - } - - /** - * Free yourself if no one is holding you. - * @update harishd 08/02/00 - */ - void Release(nsDummyAllocator& aArenaPool) { - --mUseCount; - NS_LOG_RELEASE(this, mUseCount, "CToken"); - if (mUseCount==0) - Destroy(this, aArenaPool); - } - - /** - * Default constructor - * @update gess7/21/98 - */ - CToken(int32_t aTag=0); - - /** - * Retrieve string value of the token - * @update gess5/11/98 - * @return reference to string containing string value - */ - virtual const nsSubstring& GetStringValue(void) = 0; - - /** - * Get string of full contents, suitable for debug dump. - * It should look exactly like the input source. - * @update gess5/11/98 - * @return reference to string containing string value - */ - virtual void GetSource(nsString& anOutputString); - - /** @update harishd 03/23/00 - * @return reference to string containing string value - */ - virtual void AppendSourceTo(nsAString& anOutputString); - - /** - * Sets the ordinal value of this token (not currently used) - * @update gess5/11/98 - * @param value is the new ord value for this token - */ - void SetTypeID(int32_t aValue) { - mTypeID = aValue; - } - - /** - * Getter which retrieves the current ordinal value for this token - * @update gess5/11/98 - * @return current ordinal value - */ - virtual int32_t GetTypeID(void); - - /** - * Getter which retrieves the current attribute count for this token - * @update gess5/11/98 - * @return current attribute count - */ - virtual int16_t GetAttributeCount(void); - - /** - * Causes token to consume data from given scanner. - * Note that behavior varies wildly between CToken subclasses. - * @update gess5/11/98 - * @param aChar -- most recent char consumed - * @param aScanner -- input source where token should get data - * @return error code (0 means ok) - */ - virtual nsresult Consume(PRUnichar aChar,nsScanner& aScanner,int32_t aMode); - - /** - * Getter which retrieves type of token - * @update gess5/11/98 - * @return int containing token type - */ - virtual int32_t GetTokenType(void); - - /** - * For tokens who care, this can tell us whether the token is - * well formed or not. - * - * @update gess 8/30/00 - * @return false; subclasses MUST override if they care. - */ - virtual bool IsWellFormed(void) const {return false;} - - virtual bool IsEmpty(void) { return false; } - - /** - * If aValue is TRUE then the token represents a short-hand tag - */ - virtual void SetEmpty(bool aValue) { return ; } - - int32_t GetNewlineCount() - { - return mNewlineCount; - } - - void SetNewlineCount(int32_t aCount) - { - mNewlineCount = aCount; - } - - int32_t GetLineNumber() - { - return mLineNumber; - } - - void SetLineNumber(int32_t aLineNumber) - { - mLineNumber = mLineNumber == 0 ? aLineNumber : mLineNumber; - } - - void SetInError(bool aInError) - { - mInError = aInError; - } - - bool IsInError() - { - return mInError; - } - - void SetAttributeCount(int16_t aValue) { mAttrCount = aValue; } - - /** - * perform self test. - * @update gess5/11/98 - */ - virtual void SelfTest(void); - - static int GetTokenCount(); - - - -protected: - int32_t mTypeID; - int32_t mUseCount; - int32_t mNewlineCount; - uint32_t mLineNumber : 31; - uint32_t mInError : 1; - int16_t mAttrCount; -}; - - - #endif
--- a/parser/htmlparser/src/CNavDTD.cpp +++ b/parser/htmlparser/src/CNavDTD.cpp @@ -1,2907 +1,97 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set sw=2 ts=2 et tw=78: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/Util.h" -#include "nsDebug.h" -#include "nsIAtom.h" +#include "nsISupports.h" +#include "nsISupportsImpl.h" +#include "nsIParser.h" #include "CNavDTD.h" -#include "nsHTMLTokens.h" -#include "nsCRT.h" -#include "nsParser.h" #include "nsIHTMLContentSink.h" -#include "nsScanner.h" -#include "prenv.h" -#include "prtypes.h" -#include "prio.h" -#include "plstr.h" -#include "nsDTDUtils.h" -#include "nsHTMLTokenizer.h" #include "nsParserNode.h" -#include "nsHTMLEntities.h" -#include "nsLinebreakConverter.h" -#include "nsIFormProcessor.h" -#include "nsTArray.h" -#include "nsReadableUtils.h" -#include "nsUnicharUtils.h" -#include "nsIServiceManager.h" -#include "nsParserConstants.h" -#include <algorithm> - -using namespace mozilla; - -/* - * Ignore kFontStyle and kPhrase tags when the stack is deep, bug 58917. - */ -#define FONTSTYLE_IGNORE_DEPTH (MAX_REFLOW_DEPTH * 80 / 100) -#define PHRASE_IGNORE_DEPTH (MAX_REFLOW_DEPTH * 90 / 100) -static NS_DEFINE_CID(kFormProcessorCID, NS_FORMPROCESSOR_CID); - -#ifdef DEBUG -static const char kNullToken[] = "Error: Null token given"; -static const char kInvalidTagStackPos[] = "Error: invalid tag stack position"; -#endif - -#include "nsElementTable.h" - -// Some flags for use by the DTD. -#define NS_DTD_FLAG_NONE 0x00000000 -#define NS_DTD_FLAG_HAS_OPEN_HEAD 0x00000001 -#define NS_DTD_FLAG_HAS_OPEN_BODY 0x00000002 -#define NS_DTD_FLAG_HAS_OPEN_FORM 0x00000004 -#define NS_DTD_FLAG_HAS_EXPLICIT_HEAD 0x00000008 -#define NS_DTD_FLAG_HAD_BODY 0x00000010 -#define NS_DTD_FLAG_HAD_FRAMESET 0x00000020 -#define NS_DTD_FLAG_ENABLE_RESIDUAL_STYLE 0x00000040 -#define NS_DTD_FLAG_ALTERNATE_CONTENT 0x00000080 // NOFRAMES, NOSCRIPT -#define NS_DTD_FLAG_MISPLACED_CONTENT 0x00000100 -#define NS_DTD_FLAG_IN_MISPLACED_CONTENT 0x00000200 -#define NS_DTD_FLAG_STOP_PARSING 0x00000400 - -#define NS_DTD_FLAG_HAS_MAIN_CONTAINER (NS_DTD_FLAG_HAD_BODY | \ - NS_DTD_FLAG_HAD_FRAMESET) - -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CNavDTD) - NS_INTERFACE_MAP_ENTRY(nsIDTD) - NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDTD) -NS_INTERFACE_MAP_END - -NS_IMPL_CYCLE_COLLECTING_ADDREF(CNavDTD) -NS_IMPL_CYCLE_COLLECTING_RELEASE(CNavDTD) - -NS_IMPL_CYCLE_COLLECTION_1(CNavDTD, mSink) +NS_IMPL_ISUPPORTS1(CNavDTD, nsIDTD); CNavDTD::CNavDTD() - : mMisplacedContent(0), - mTokenAllocator(0), - mBodyContext(new nsDTDContext()), - mTempContext(0), - mCountLines(true), - mTokenizer(0), - mDTDMode(eDTDMode_quirks), - mDocType(eHTML_Quirks), - mParserCommand(eViewNormal), - mLineNumber(1), - mOpenMapCount(0), - mHeadContainerPosition(-1), - mFlags(NS_DTD_FLAG_NONE) { } CNavDTD::~CNavDTD() { - delete mBodyContext; - delete mTempContext; } NS_IMETHODIMP CNavDTD::WillBuildModel(const CParserContext& aParserContext, nsITokenizer* aTokenizer, nsIContentSink* aSink) { - nsresult result = NS_OK; - - mFilename = aParserContext.mScanner->GetFilename(); - mFlags = NS_DTD_FLAG_ENABLE_RESIDUAL_STYLE; - mLineNumber = 1; - mDTDMode = aParserContext.mDTDMode; - mParserCommand = aParserContext.mParserCommand; - mMimeType = aParserContext.mMimeType; - mDocType = aParserContext.mDocType; - mTokenizer = aTokenizer; - mBodyContext->SetNodeAllocator(&mNodeAllocator); - - if (!aParserContext.mPrevContext && aSink) { - - if (!mSink) { - mSink = do_QueryInterface(aSink, &result); - if (NS_FAILED(result)) { - mFlags |= NS_DTD_FLAG_STOP_PARSING; - return result; - } - } - - mFlags |= nsHTMLTokenizer::GetFlags(aSink); - - } - - return result; + return NS_OK; } NS_IMETHODIMP CNavDTD::BuildModel(nsITokenizer* aTokenizer, - bool aCountLines, - const nsCString*) + nsIContentSink* aSink) { - NS_PRECONDITION(mBodyContext != nullptr, - "Create a context before calling build model"); - - nsresult result = NS_OK; - - if (!aTokenizer) { - return NS_OK; - } - - nsITokenizer* const oldTokenizer = mTokenizer; - - mCountLines = aCountLines; - mTokenizer = aTokenizer; - mTokenAllocator = mTokenizer->GetTokenAllocator(); - - if (!mSink) { - return (mFlags & NS_DTD_FLAG_STOP_PARSING) - ? NS_ERROR_HTMLPARSER_STOPPARSING - : result; + // NB: It is important to throw STOPPARSING if the sink is the wrong type in + // order to make sure nsParser cleans up properly after itself. + nsCOMPtr<nsIHTMLContentSink> sink = do_QueryInterface(aSink); + if (!sink) { + return NS_ERROR_HTMLPARSER_STOPPARSING; } - if (mBodyContext->GetCount() == 0) { - CToken* tempToken; - if (ePlainText == mDocType) { - tempToken = - mTokenAllocator->CreateTokenOfType(eToken_start, eHTMLTag_pre); - if (tempToken) { - mTokenizer->PushTokenFront(tempToken); - } - } - - // Always open a body if frames are disabled. - if (!(mFlags & NS_IPARSER_FLAG_FRAMES_ENABLED)) { - tempToken = - mTokenAllocator->CreateTokenOfType(eToken_start, - eHTMLTag_body, - NS_LITERAL_STRING("body")); - if (tempToken) { - mTokenizer->PushTokenFront(tempToken); - } - } + nsParserNode html(eHTMLTag_html); + nsParserNode body(eHTMLTag_body); - // If the content model is empty, then begin by opening <html>. - CStartToken* theToken = (CStartToken*)mTokenizer->GetTokenAt(0); - if (theToken) { - eHTMLTags theTag = (eHTMLTags)theToken->GetTypeID(); - eHTMLTokenTypes theType = eHTMLTokenTypes(theToken->GetTokenType()); - if (theTag != eHTMLTag_html || theType != eToken_start) { - tempToken = - mTokenAllocator->CreateTokenOfType(eToken_start, - eHTMLTag_html, - NS_LITERAL_STRING("html")); - if (tempToken) { - mTokenizer->PushTokenFront(tempToken); - } - } - } else { - tempToken = - mTokenAllocator->CreateTokenOfType(eToken_start, - eHTMLTag_html, - NS_LITERAL_STRING("html")); - if (tempToken) { - mTokenizer->PushTokenFront(tempToken); - } - } - } + nsresult rv = sink->OpenContainer(html); + NS_ENSURE_SUCCESS(rv, rv); + rv = sink->OpenContainer(body); + NS_ENSURE_SUCCESS(rv, rv); - while (NS_SUCCEEDED(result)) { - if (!(mFlags & NS_DTD_FLAG_STOP_PARSING)) { - CToken* theToken = mTokenizer->PopToken(); - if (!theToken) { - break; - } - result = HandleToken(theToken); - } else { - result = NS_ERROR_HTMLPARSER_STOPPARSING; - break; - } + rv = sink->CloseContainer(eHTMLTag_body); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + rv = sink->CloseContainer(eHTMLTag_html); + MOZ_ASSERT(NS_SUCCEEDED(rv)); - if (NS_ERROR_HTMLPARSER_INTERRUPTED == mSink->DidProcessAToken()) { - // The content sink has requested that DTD interrupt processing tokens - // We need to make sure that an interruption does not override - // a request to block the parser. - if (NS_SUCCEEDED(result)) { - result = NS_ERROR_HTMLPARSER_INTERRUPTED; - break; - } - } - } - - mTokenizer = oldTokenizer; - return result; -} - -nsresult -CNavDTD::BuildNeglectedTarget(eHTMLTags aTarget, - eHTMLTokenTypes aType) -{ - NS_ASSERTION(mTokenizer, "tokenizer is null! unable to build target."); - NS_ASSERTION(mTokenAllocator, "unable to create tokens without an allocator."); - if (!mTokenizer || !mTokenAllocator) { - return NS_OK; - } - - CToken* target = mTokenAllocator->CreateTokenOfType(aType, aTarget); - NS_ENSURE_TRUE(target, NS_ERROR_OUT_OF_MEMORY); - mTokenizer->PushTokenFront(target); - // Also, BuildModel - // doesn't seem to care about the charset, and at this point we have no idea - // what the charset was, so 0 can and must suffice. - return BuildModel(mTokenizer, mCountLines, 0); + return NS_OK; } NS_IMETHODIMP CNavDTD::DidBuildModel(nsresult anErrorCode) { - nsresult result = NS_OK; - - if (mSink) { - if (NS_OK == anErrorCode) { - if (!(mFlags & NS_DTD_FLAG_HAS_MAIN_CONTAINER)) { - // This document is not a frameset document, however, it did not contain - // a body tag either. So, make one!. Note: Body tag is optional per spec.. - // Also note: We ignore the return value of BuildNeglectedTarget, we - // can't reasonably respond to errors (or requests to block) at this - // point in the parsing process. - BuildNeglectedTarget(eHTMLTag_body, eToken_start); - } - if (mFlags & NS_DTD_FLAG_MISPLACED_CONTENT) { - // Looks like the misplaced contents are not processed yet. - // Here is our last chance to handle the misplaced content. - - // Keep track of the top index. - int32_t topIndex = mBodyContext->mContextTopIndex; - - // Loop until we've really consumed all of our misplaced content. - do { - mFlags &= ~NS_DTD_FLAG_MISPLACED_CONTENT; - - // mContextTopIndex refers to the misplaced content's legal parent index. - result = HandleSavedTokens(mBodyContext->mContextTopIndex); - if (NS_FAILED(result)) { - NS_ERROR("Bug in the DTD"); - break; - } - - // If we start handling misplaced content while handling misplaced - // content, mContextTopIndex gets modified. However, this new index - // necessarily points to the middle of a closed tag (since we close - // new tags after handling the misplaced content). So we restore the - // insertion point after every iteration. - mBodyContext->mContextTopIndex = topIndex; - } while (mFlags & NS_DTD_FLAG_MISPLACED_CONTENT); - - mBodyContext->mContextTopIndex = -1; - } - - // Now let's disable style handling to save time when closing remaining - // stack members. - mFlags &= ~NS_DTD_FLAG_ENABLE_RESIDUAL_STYLE; - while (mBodyContext->GetCount() > 0) { - result = CloseContainersTo(mBodyContext->Last(), false); - NS_ENSURE_SUCCESS(result, result); - } - } else { - // If you're here, then an error occurred, but we still have nodes on the stack. - // At a minimum, we should grab the nodes and recycle them. - // Just to be correct, we'll also recycle the nodes. - while (mBodyContext->GetCount() > 0) { - nsEntryStack* theChildStyles = 0; - nsCParserNode* theNode = mBodyContext->Pop(theChildStyles); - IF_DELETE(theChildStyles, &mNodeAllocator); - IF_FREE(theNode, &mNodeAllocator); - } - } - - // Now make sure the misplaced content list is empty, - // by forcefully recycling any tokens we might find there. - CToken* theToken = 0; - while ((theToken = (CToken*)mMisplacedContent.Pop())) { - IF_FREE(theToken, mTokenAllocator); - } - } - - return result; + return NS_OK; } -NS_IMETHODIMP_(void) -CNavDTD::Terminate() -{ - mFlags |= NS_DTD_FLAG_STOP_PARSING; +NS_IMETHODIMP_(void) +CNavDTD::Terminate() +{ } NS_IMETHODIMP_(int32_t) CNavDTD::GetType() { return NS_IPARSER_FLAG_HTML; } NS_IMETHODIMP_(nsDTDMode) CNavDTD::GetMode() const { - return mDTDMode; -} - -/** - * Text and some tags require a body when they're added, this function returns - * true for those tags. - * - * @param aToken The current token that we care about. - * @param aTokenizer A tokenizer that we can get the tags attributes off of. - * @return true if aToken does indeed force the body to open. - */ -static bool -DoesRequireBody(CToken* aToken, nsITokenizer* aTokenizer) -{ - bool result = false; - - if (aToken) { - eHTMLTags theTag = (eHTMLTags)aToken->GetTypeID(); - if (gHTMLElements[theTag].HasSpecialProperty(kRequiresBody)) { - if (theTag == eHTMLTag_input) { - // IE & Nav4x opens up a body for type=text - Bug 66985 - // XXXbz but we don't want to open one for <input> with no - // type attribute? That's pretty whack. - int32_t ac = aToken->GetAttributeCount(); - for(int32_t i = 0; i < ac; ++i) { - CAttributeToken* attr = static_cast<CAttributeToken*> - (aTokenizer->GetTokenAt(i)); - const nsSubstring& name = attr->GetKey(); - const nsAString& value = attr->GetValue(); - // XXXbz note that this stupid case-sensitive comparison is - // actually depended on by sites... - if ((name.EqualsLiteral("type") || - name.EqualsLiteral("TYPE")) - && - !(value.EqualsLiteral("hidden") || - value.EqualsLiteral("HIDDEN"))) { - result = true; - break; - } - } - } else { - result = true; - } - } - } - - return result; + return eDTDMode_quirks; } -static bool -ValueIsHidden(const nsAString& aValue) -{ - // Having to deal with whitespace here sucks, but we have to match - // what the content sink does. - nsAutoString str(aValue); - str.Trim("\n\r\t\b"); - return str.LowerCaseEqualsLiteral("hidden"); -} - -// Check whether aToken corresponds to a <input type="hidden"> tag. The token -// must be a start tag token for an <input>. This must be called at a point -// when all the attributes for the input are still in the tokenizer. -static bool -IsHiddenInput(CToken* aToken, nsITokenizer* aTokenizer) +NS_IMETHODIMP_(bool) +CNavDTD::CanContain(int32_t aParent,int32_t aChild) const { - NS_PRECONDITION(eHTMLTokenTypes(aToken->GetTokenType()) == eToken_start, - "Must be start token"); - NS_PRECONDITION(eHTMLTags(aToken->GetTypeID()) == eHTMLTag_input, - "Must be <input> tag"); - - int32_t ac = aToken->GetAttributeCount(); - NS_ASSERTION(ac <= aTokenizer->GetCount(), - "Not enough tokens in the tokenizer"); - // But we don't really trust ourselves to get that right - ac = std::min(ac, aTokenizer->GetCount()); - - for (int32_t i = 0; i < ac; ++i) { - NS_ASSERTION(eHTMLTokenTypes(aTokenizer->GetTokenAt(i)->GetTokenType()) == - eToken_attribute, "Unexpected token type"); - // Again, we're not sure we actually manage to guarantee that - if (eHTMLTokenTypes(aTokenizer->GetTokenAt(i)->GetTokenType()) != - eToken_attribute) { - break; - } - - CAttributeToken* attrToken = - static_cast<CAttributeToken*>(aTokenizer->GetTokenAt(i)); - if (!attrToken->GetKey().LowerCaseEqualsLiteral("type")) { - continue; - } - - return ValueIsHidden(attrToken->GetValue()); - } - - return false; -} - -/** - * Returns whether or not there is a tag of type aType open on aContext. - */ -static bool -HasOpenTagOfType(int32_t aType, const nsDTDContext& aContext) -{ - int32_t count = aContext.GetCount(); - - while (--count >= 0) { - if (gHTMLElements[aContext.TagAt(count)].IsMemberOf(aType)) { - return true; - } - } - + MOZ_CRASH("nobody calls this"); return false; } -nsresult -CNavDTD::HandleToken(CToken* aToken) -{ - if (!aToken) { - return NS_OK; - } - - nsresult result = NS_OK; - CHTMLToken* theToken = static_cast<CHTMLToken*>(aToken); - eHTMLTokenTypes theType = eHTMLTokenTypes(theToken->GetTokenType()); - eHTMLTags theTag = (eHTMLTags)theToken->GetTypeID(); - - aToken->SetLineNumber(mLineNumber); - - if (mCountLines) { - mLineNumber += aToken->GetNewlineCount(); - } - - if (mFlags & NS_DTD_FLAG_MISPLACED_CONTENT) { - // Included TD & TH to fix Bug# 20797 - static eHTMLTags gLegalElements[] = { - eHTMLTag_table, eHTMLTag_thead, eHTMLTag_tbody, - eHTMLTag_tr, eHTMLTag_td, eHTMLTag_th, eHTMLTag_tfoot - }; - // Don't even try processing misplaced tokens if we're already - // handling misplaced content. See bug 269095 - if (mFlags & NS_DTD_FLAG_IN_MISPLACED_CONTENT) { - PushIntoMisplacedStack(theToken); - return NS_OK; - } - - eHTMLTags theParentTag = mBodyContext->Last(); - if (FindTagInSet(theTag, gLegalElements, - ArrayLength(gLegalElements)) || - (gHTMLElements[theParentTag].CanContain(theTag, mDTDMode) && - // Here's a problem. If theTag is legal in here, we don't move it - // out. So if we're moving stuff out of here, the parent of theTag - // gets closed at this point. But some things are legal - // _everywhere_ and hence would effectively close out misplaced - // content in tables. This is undesirable, so treat them as - // illegal here so they'll be shipped out with their parents and - // siblings. See bug 40855 for an explanation (that bug was for - // comments, but the same issues arise with whitespace, newlines, - // noscript, etc). Script is special, though. Shipping it out - // breaks document.write stuff. See bug 243064. - (!gHTMLElements[theTag].HasSpecialProperty(kLegalOpen) || - theTag == eHTMLTag_script)) || - (theTag == eHTMLTag_input && theType == eToken_start && - FindTagInSet(theParentTag, gLegalElements, - ArrayLength(gLegalElements)) && - IsHiddenInput(theToken, mTokenizer))) { - // Reset the state since all the misplaced tokens are about to get - // handled. - mFlags &= ~NS_DTD_FLAG_MISPLACED_CONTENT; - - result = HandleSavedTokens(mBodyContext->mContextTopIndex); - NS_ENSURE_SUCCESS(result, result); - - mBodyContext->mContextTopIndex = -1; - } else { - PushIntoMisplacedStack(theToken); - return result; - } - } - - /* - * This section of code is used to "move" misplaced content from one location - * in our document model to another. (Consider what would happen if we found a - * <P> tag in the head.) To move content, we throw it onto the - * misplacedcontent deque until we can deal with it. - */ - switch(theTag) { - case eHTMLTag_html: - case eHTMLTag_noframes: - case eHTMLTag_script: - case eHTMLTag_doctypeDecl: - case eHTMLTag_instruction: - break; - - default: - if (!gHTMLElements[eHTMLTag_html].SectionContains(theTag, false)) { - if (!(mFlags & (NS_DTD_FLAG_HAS_MAIN_CONTAINER | - NS_DTD_FLAG_ALTERNATE_CONTENT))) { - // For bug examples from this code, see bugs: 18928, 20989. - // At this point we know the body/frameset aren't open. - // If the child belongs in the head, then handle it (which may open - // the head); otherwise, push it onto the misplaced stack. - - bool isExclusive = false; - bool theChildBelongsInHead = - gHTMLElements[eHTMLTag_head].IsChildOfHead(theTag, isExclusive); - if (theChildBelongsInHead && - !isExclusive && - !gHTMLElements[theTag].HasSpecialProperty(kPreferHead)) { - if (mMisplacedContent.GetSize() == 0 && - (!gHTMLElements[theTag].HasSpecialProperty(kPreferBody) || - (mFlags & NS_DTD_FLAG_HAS_EXPLICIT_HEAD))) { - // This tag can either be in the body or the head. Since - // there is no indication that the body should be open, - // put this token in the head. - break; - } - - // Otherwise, we have received some indication that the body is - // "open", so push this token onto the misplaced content stack. - theChildBelongsInHead = false; - } - - if (!theChildBelongsInHead) { - eHTMLTags top = mBodyContext->Last(); - NS_ASSERTION(top != eHTMLTag_userdefined, - "Userdefined tags should act as leaves in the head"); - if (top != eHTMLTag_html && top != eHTMLTag_head && - gHTMLElements[top].CanContain(theTag, mDTDMode)) { - // Some tags (such as <object> and <script>) are opened in the - // head and allow other non-head content to be children. - // Note: Userdefined tags in the head act like leaves. - break; - } - - // If you're here then we found a child of the body that was out of - // place. We're going to move it to the body by storing it - // temporarily on the misplaced stack. However, in quirks mode, a - // few tags request, ambiguosly, for a BODY. - Bugs 18928, 24204.- - PushIntoMisplacedStack(aToken); - - if (IsAlternateTag(theTag)) { - // These tags' contents are consumed as CDATA. If we simply - // pushed them on the misplaced content stack, the CDATA - // contents would force us to open a body, which could be - // wrong. So we collect the whole tag as misplaced in one - // gulp. Note that the tokenizer guarantees that there will - // be an end tag. - CToken *current = aToken; - while (current->GetTokenType() != eToken_end || - current->GetTypeID() != theTag) { - current = static_cast<CToken *>(mTokenizer->PopToken()); - NS_ASSERTION(current, "The tokenizer is not creating good " - "alternate tags"); - PushIntoMisplacedStack(current); - } - - // XXX Add code to also collect incorrect attributes on the - // end tag. - } - - if (DoesRequireBody(aToken, mTokenizer)) { - CToken* theBodyToken = - mTokenAllocator->CreateTokenOfType(eToken_start, - eHTMLTag_body, - NS_LITERAL_STRING("body")); - result = HandleToken(theBodyToken); - } - return result; - } - } - } - } - - if (theToken) { - switch (theType) { - case eToken_text: - case eToken_start: - case eToken_whitespace: - case eToken_newline: - result = HandleStartToken(theToken); - break; - - case eToken_end: - result = HandleEndToken(theToken); - break; - - case eToken_cdatasection: - case eToken_comment: - case eToken_markupDecl: - result = HandleCommentToken(theToken); - break; - - case eToken_entity: - result = HandleEntityToken(theToken); - break; - - case eToken_attribute: - result = HandleAttributeToken(theToken); - break; - - case eToken_instruction: - result = HandleProcessingInstructionToken(theToken); - break; - - case eToken_doctypeDecl: - result = HandleDocTypeDeclToken(theToken); - break; - - default: - break; - } - - IF_FREE(theToken, mTokenAllocator); - if (result == NS_ERROR_HTMLPARSER_STOPPARSING) { - mFlags |= NS_DTD_FLAG_STOP_PARSING; - } else if (NS_FAILED(result) && result != NS_ERROR_HTMLPARSER_BLOCK) { - result = NS_OK; - } - } - - return result; -} - -nsresult -CNavDTD::DidHandleStartTag(nsIParserNode& aNode, eHTMLTags aChildTag) -{ - nsresult result = NS_OK; - - switch (aChildTag) { - case eHTMLTag_pre: - case eHTMLTag_listing: - { - // Skip the 1st newline inside PRE and LISTING unless this is a - // plain text doc (for which we pushed a PRE in CNavDTD::BuildModel). - - // XXX This code is incorrect in the face of misplaced <pre> and - // <listing> tags (as direct children of <table>). - CToken* theNextToken = mTokenizer->PeekToken(); - if (ePlainText != mDocType && theNextToken) { - eHTMLTokenTypes theType = eHTMLTokenTypes(theNextToken->GetTokenType()); - if (eToken_newline == theType) { - if (mCountLines) { - mLineNumber += theNextToken->GetNewlineCount(); - } - theNextToken = mTokenizer->PopToken(); - IF_FREE(theNextToken, mTokenAllocator); // fix for Bug 29379 - } - } - } - break; - - default: - break; - } - - return result; -} - -int32_t -CNavDTD::LastOf(eHTMLTags aTagSet[], int32_t aCount) const -{ - for (int32_t theIndex = mBodyContext->GetCount() - 1; theIndex >= 0; - --theIndex) { - if (FindTagInSet((*mBodyContext)[theIndex], aTagSet, aCount)) { - return theIndex; - } - } - - return kNotFound; -} - -static bool -CanBeContained(eHTMLTags aChildTag, nsDTDContext& aContext) -{ - /* # Interesting test cases: Result: - * 1. <UL><LI>..<B>..<LI> inner <LI> closes outer <LI> - * 2. <CENTER><DL><DT><A><CENTER> allow nested <CENTER> - * 3. <TABLE><TR><TD><TABLE>... allow nested <TABLE> - * 4. <FRAMESET> ... <FRAMESET> - */ - bool result = true; - int32_t theCount = aContext.GetCount(); - - if (0 < theCount) { - const TagList* theRootTags = gHTMLElements[aChildTag].GetRootTags(); - const TagList* theSpecialParents = - gHTMLElements[aChildTag].GetSpecialParents(); - - if (theRootTags) { - int32_t theRootIndex = LastOf(aContext, *theRootTags); - int32_t theSPIndex = theSpecialParents - ? LastOf(aContext, *theSpecialParents) - : kNotFound; - int32_t theChildIndex = - nsHTMLElement::GetIndexOfChildOrSynonym(aContext, aChildTag); - int32_t theTargetIndex = (theRootIndex > theSPIndex) - ? theRootIndex - : theSPIndex; - - if (theTargetIndex == theCount-1 || - (theTargetIndex == theChildIndex && - gHTMLElements[aChildTag].CanContainSelf())) { - result = true; - } else { - result = false; - - static eHTMLTags gTableElements[] = { eHTMLTag_td, eHTMLTag_th }; - - int32_t theIndex = theCount - 1; - while (theChildIndex < theIndex) { - eHTMLTags theParentTag = aContext.TagAt(theIndex--); - if (gHTMLElements[theParentTag].IsMemberOf(kBlockEntity) || - gHTMLElements[theParentTag].IsMemberOf(kHeading) || - gHTMLElements[theParentTag].IsMemberOf(kPreformatted) || - gHTMLElements[theParentTag].IsMemberOf(kFormControl) || //fixes bug 44479 - gHTMLElements[theParentTag].IsMemberOf(kList)) { - if (!HasOptionalEndTag(theParentTag)) { - result = true; - break; - } - } else if (FindTagInSet(theParentTag, gTableElements, - ArrayLength(gTableElements))) { - // Added this to catch a case we missed; bug 57173. - result = true; - break; - } - } - } - } - } - - return result; -} - -enum eProcessRule { eNormalOp, eLetInlineContainBlock }; - -nsresult -CNavDTD::HandleDefaultStartToken(CToken* aToken, eHTMLTags aChildTag, - nsCParserNode *aNode) -{ - NS_PRECONDITION(nullptr != aToken, kNullToken); - - nsresult result = NS_OK; - bool theChildIsContainer = nsHTMLElement::IsContainer(aChildTag); - - // Client of parser is spefically trying to parse a fragment that - // may lack required context. Suspend containment rules if so. - if (mParserCommand != eViewFragment) { - bool theChildAgrees = true; - int32_t theIndex = mBodyContext->GetCount(); - int32_t theParentContains = 0; - - do { - eHTMLTags theParentTag = mBodyContext->TagAt(--theIndex); - if (theParentTag == eHTMLTag_userdefined) { - continue; - } - - // Figure out whether this is a hidden input inside a - // table/tbody/thead/tfoot/tr - static eHTMLTags sTableElements[] = { - eHTMLTag_table, eHTMLTag_thead, eHTMLTag_tbody, - eHTMLTag_tr, eHTMLTag_tfoot - }; - - bool isHiddenInputInsideTableElement = false; - if (aChildTag == eHTMLTag_input && - FindTagInSet(theParentTag, sTableElements, - ArrayLength(sTableElements))) { - int32_t attrCount = aNode->GetAttributeCount(); - for (int32_t attrIndex = 0; attrIndex < attrCount; ++attrIndex) { - const nsAString& key = aNode->GetKeyAt(attrIndex); - if (key.LowerCaseEqualsLiteral("type")) { - isHiddenInputInsideTableElement = - ValueIsHidden(aNode->GetValueAt(attrIndex)); - break; - } - } - } - - // Precompute containment, and pass it to CanOmit()... - theParentContains = - isHiddenInputInsideTableElement || CanContain(theParentTag, aChildTag); - if (!isHiddenInputInsideTableElement && - CanOmit(theParentTag, aChildTag, theParentContains)) { - HandleOmittedTag(aToken, aChildTag, theParentTag, aNode); - return NS_OK; - } - - eProcessRule theRule = eNormalOp; - - if (!theParentContains && - (IsBlockElement(aChildTag, theParentTag) && - IsInlineElement(theParentTag, theParentTag))) { - // Don't test for table to fix 57554. - if (eHTMLTag_li != aChildTag) { - nsCParserNode* theParentNode = mBodyContext->PeekNode(); - if (theParentNode && theParentNode->mToken->IsWellFormed()) { - theRule = eLetInlineContainBlock; - } - } - } - - switch (theRule) { - case eNormalOp: - theChildAgrees = true; - if (theParentContains) { - eHTMLTags theAncestor = gHTMLElements[aChildTag].mRequiredAncestor; - if (eHTMLTag_unknown != theAncestor) { - theChildAgrees = HasOpenContainer(theAncestor); - } - - if (theChildAgrees && theChildIsContainer) { - if (theParentTag != aChildTag) { - // Double check the power structure - // Note: The bit is currently set on tags such as <A> and <LI>. - if (gHTMLElements[aChildTag].ShouldVerifyHierarchy()) { - int32_t theChildIndex = - nsHTMLElement::GetIndexOfChildOrSynonym(*mBodyContext, - aChildTag); - - if (kNotFound < theChildIndex && theChildIndex < theIndex) { - /* - * 1 Here's a tricky case from bug 22596: <h5><li><h5> - * How do we know that the 2nd <h5> should close the <LI> - * rather than nest inside the <LI>? (Afterall, the <h5> - * is a legal child of the <LI>). - * - * The way you know is that there is no root between the - * two, so the <h5> binds more tightly to the 1st <h5> - * than to the <LI>. - * - * 2 Also, bug 6148 shows this case: <SPAN><DIV><SPAN> - * From this case we learned not to execute this logic if - * the parent is a block. - * - * 3 Fix for 26583: - * <A href=foo.html><B>foo<A href-bar.html>bar</A></B></A> - * In the above example clicking on "foo" or "bar" should - * link to foo.html or bar.html respectively. That is, - * the inner <A> should be informed about the presence of - * an open <A> above <B>..so that the inner <A> can close - * out the outer <A>. The following code does it for us. - * - * 4 Fix for 27865 [ similer to 22596 ]. Ex: - * <DL><DD><LI>one<DD><LI>two - */ - theChildAgrees = CanBeContained(aChildTag, *mBodyContext); - } - } - } - } - } - - if (!(theParentContains && theChildAgrees)) { - if (!CanPropagate(theParentTag, aChildTag, theParentContains)) { - if (theChildIsContainer || !theParentContains) { - if (!theChildAgrees && - !gHTMLElements[aChildTag].CanAutoCloseTag(*mBodyContext, - theIndex, - aChildTag)) { - // Closing the tags above might cause non-compatible results. - // Ex. <TABLE><TR><TD><TBODY>Text</TD></TR></TABLE>. - // In the example above <TBODY> is badly misplaced, but - // we should not attempt to close the tags above it, - // The safest thing to do is to discard this tag. - // XXX We get the above example wrong anyway because of - // CanBeContained. - return result; - } else if (mBodyContext->mContextTopIndex > 0 && - theIndex <= mBodyContext->mContextTopIndex) { - // Looks like the parent tag does not want to contain the - // current tag ( aChildTag ). However, we have to force the - // containment, when handling misplaced content, to avoid data - // loss. Ref. bug 138577. - theParentContains = true; - } else { - CloseContainersTo(theIndex, aChildTag, true); - } - } else { - break; - } - } else { - CreateContextStackFor(theParentTag, aChildTag); - theIndex = mBodyContext->GetCount(); - } - } - break; - - case eLetInlineContainBlock: - // Break out of this loop and open the block. - theParentContains = theChildAgrees = true; - break; - - default: - NS_NOTREACHED("Invalid rule detected"); - } - } while (!(theParentContains && theChildAgrees)); - } - - if (theChildIsContainer) { - result = OpenContainer(aNode, aChildTag); - } else { - result = AddLeaf(aNode); - } - - return result; -} - -nsresult -CNavDTD::WillHandleStartTag(CToken* aToken, eHTMLTags aTag, - nsIParserNode& aNode) -{ - nsresult result = NS_OK; - - int32_t stackDepth = mBodyContext->GetCount(); - if (stackDepth >= FONTSTYLE_IGNORE_DEPTH && - gHTMLElements[aTag].IsMemberOf(kFontStyle)) { - // Prevent bug 58917 by tossing the new kFontStyle start tag - return kHierarchyTooDeep; - } - - if (stackDepth >= PHRASE_IGNORE_DEPTH && - gHTMLElements[aTag].IsMemberOf(kPhrase)) { - // Prevent bug 58917 by tossing the new kPhrase start tag - return kHierarchyTooDeep; - } - - /* - * Now a little code to deal with bug #49687 (crash when layout stack gets - * too deep) I've also opened this up to any container (not just inlines): - * re bug 55095 Improved to handle bug 55980 (infinite loop caused when - * DEPTH is exceeded and </P> is encountered by itself (<P>) is continuously - * produced. - */ - if (stackDepth > MAX_REFLOW_DEPTH) { - if (nsHTMLElement::IsContainer(aTag) && - !gHTMLElements[aTag].HasSpecialProperty(kHandleStrayTag)) { - // Ref. bug 98261,49678,55095,55980 - // Instead of throwing away the current tag close it's parent - // such that the stack level does not go beyond the max_reflow_depth. - // This would allow leaf tags, that follow the current tag, to find - // the correct node. - while (stackDepth != MAX_REFLOW_DEPTH && NS_SUCCEEDED(result)) { - result = CloseContainersTo(mBodyContext->Last(), false); - --stackDepth; - } - } - } - - return result; -} - -static void -PushMisplacedAttributes(nsIParserNode& aNode, nsDeque& aDeque) -{ - nsCParserNode& theAttrNode = static_cast<nsCParserNode &>(aNode); - - for (int32_t count = aNode.GetAttributeCount(); count > 0; --count) { - CToken* theAttrToken = theAttrNode.PopAttributeTokenFront(); - if (theAttrToken) { - theAttrToken->SetNewlineCount(0); - aDeque.Push(theAttrToken); - } - } -} - -void -CNavDTD::HandleOmittedTag(CToken* aToken, eHTMLTags aChildTag, - eHTMLTags aParent, nsIParserNode* aNode) -{ - NS_PRECONDITION(mBodyContext != nullptr, "need a context to work with"); - - // The trick here is to see if the parent can contain the child, but prefers - // not to. Only if the parent CANNOT contain the child should we look to see - // if it's potentially a child of another section. If it is, the cache it for - // later. - int32_t theTagCount = mBodyContext->GetCount(); - bool pushToken = false; - - if (gHTMLElements[aParent].HasSpecialProperty(kBadContentWatch) && - !nsHTMLElement::IsWhitespaceTag(aChildTag)) { - eHTMLTags theTag = eHTMLTag_unknown; - - // Don't bother saving misplaced stuff in the head. This can happen in - // cases like |<head><noscript><table>foo|. See bug 401169. - if (mFlags & NS_DTD_FLAG_HAS_OPEN_HEAD) { - NS_ASSERTION(!(mFlags & NS_DTD_FLAG_HAS_MAIN_CONTAINER), - "Bad state"); - return; - } - - // Determine the insertion point - while (theTagCount > 0) { - theTag = mBodyContext->TagAt(--theTagCount); - if (!gHTMLElements[theTag].HasSpecialProperty(kBadContentWatch)) { - // This is our insertion point. - mBodyContext->mContextTopIndex = theTagCount; - break; - } - } - - if (mBodyContext->mContextTopIndex > -1) { - pushToken = true; - - // Remember that we've stashed some misplaced content. - mFlags |= NS_DTD_FLAG_MISPLACED_CONTENT; - } - } - - if (aChildTag != aParent && - gHTMLElements[aParent].HasSpecialProperty(kSaveMisplaced)) { - NS_ASSERTION(!pushToken, "A strange element has both kBadContentWatch " - "and kSaveMisplaced"); - pushToken = true; - } - - if (pushToken) { - // Hold on to this token for later use. Ref Bug. 53695 - IF_HOLD(aToken); - PushIntoMisplacedStack(aToken); - - // If the token is attributed then save those attributes too. - PushMisplacedAttributes(*aNode, mMisplacedContent); - } -} - -/** - * This method gets called when a kegen token is found. - * - * @update harishd 05/02/00 - * @param aNode -- CParserNode representing keygen - * @return NS_OK if all went well; ERROR if error occurred - */ -nsresult -CNavDTD::HandleKeyGen(nsIParserNode* aNode) -{ - nsresult result = NS_OK; - - nsCOMPtr<nsIFormProcessor> theFormProcessor = - do_GetService(kFormProcessorCID, &result); - if (NS_FAILED(result)) { - return result; - } - - int32_t theAttrCount = aNode->GetAttributeCount(); - nsTArray<nsString> theContent; - nsAutoString theAttribute; - nsAutoString theFormType; - CToken* theToken = nullptr; - - theFormType.AssignLiteral("select"); - - result = theFormProcessor->ProvideContent(theFormType, theContent, - theAttribute); - if (NS_FAILED(result)) { - return result; - } - int32_t theIndex = 0; - - // Populate the tokenizer with the fabricated elements in the reverse - // order such that <SELECT> is on the top fo the tokenizer followed by - // <OPTION>s and </SELECT>. - theToken = mTokenAllocator->CreateTokenOfType(eToken_end, - eHTMLTag_select); - NS_ENSURE_TRUE(theToken, NS_ERROR_OUT_OF_MEMORY); - mTokenizer->PushTokenFront(theToken); - - for (theIndex = theContent.Length()-1; theIndex > -1; --theIndex) { - theToken = mTokenAllocator->CreateTokenOfType(eToken_text, - eHTMLTag_text, - theContent[theIndex]); - NS_ENSURE_TRUE(theToken, NS_ERROR_OUT_OF_MEMORY); - mTokenizer->PushTokenFront(theToken); - - theToken = mTokenAllocator->CreateTokenOfType(eToken_start, - eHTMLTag_option); - NS_ENSURE_TRUE(theToken, NS_ERROR_OUT_OF_MEMORY); - mTokenizer->PushTokenFront(theToken); - } - - // The attribute ( provided by the form processor ) should be a part - // of the SELECT. Placing the attribute token on the tokenizer to get - // picked up by the SELECT. - theToken = mTokenAllocator->CreateTokenOfType(eToken_attribute, - eHTMLTag_unknown, - theAttribute); - NS_ENSURE_TRUE(theToken, NS_ERROR_OUT_OF_MEMORY); - - ((CAttributeToken*)theToken)->SetKey(NS_LITERAL_STRING("_moz-type")); - mTokenizer->PushTokenFront(theToken); - - // Pop out NAME and CHALLENGE attributes ( from the keygen NODE ) and - // place it in the tokenizer such that the attribtues get sucked into - // SELECT node. - for (theIndex = theAttrCount; theIndex > 0; --theIndex) { - mTokenizer->PushTokenFront(((nsCParserNode*)aNode)->PopAttributeToken()); - } - - theToken = mTokenAllocator->CreateTokenOfType(eToken_start, - eHTMLTag_select); - NS_ENSURE_TRUE(theToken, NS_ERROR_OUT_OF_MEMORY); - - // Increment the count because of the additional attribute from the form processor. - theToken->SetAttributeCount(theAttrCount + 1); - mTokenizer->PushTokenFront(theToken); - - return result; -} - -bool -CNavDTD::IsAlternateTag(eHTMLTags aTag) -{ - switch (aTag) { - case eHTMLTag_noembed: - return true; - - case eHTMLTag_noscript: - return (mFlags & NS_IPARSER_FLAG_SCRIPT_ENABLED) != 0; - - case eHTMLTag_iframe: - case eHTMLTag_noframes: - return (mFlags & NS_IPARSER_FLAG_FRAMES_ENABLED) != 0; - - default: - return false; - } -} - -nsresult -CNavDTD::HandleStartToken(CToken* aToken) -{ - NS_PRECONDITION(nullptr != aToken, kNullToken); - - nsCParserNode* theNode = mNodeAllocator.CreateNode(aToken, mTokenAllocator); - NS_ENSURE_TRUE(theNode, NS_ERROR_OUT_OF_MEMORY); - - eHTMLTags theChildTag = (eHTMLTags)aToken->GetTypeID(); - int16_t attrCount = aToken->GetAttributeCount(); - eHTMLTags theParent = mBodyContext->Last(); - nsresult result = NS_OK; - - if (attrCount > 0) { - result = CollectAttributes(theNode, theChildTag, attrCount); - } - - if (NS_OK == result) { - result = WillHandleStartTag(aToken, theChildTag, *theNode); - if (NS_OK == result) { - bool isTokenHandled = false; - bool theHeadIsParent = false; - - if (nsHTMLElement::IsSectionTag(theChildTag)) { - switch (theChildTag) { - case eHTMLTag_html: - if (mBodyContext->GetCount() > 0) { - result = OpenContainer(theNode, theChildTag); - isTokenHandled = true; - } - break; - - case eHTMLTag_body: - if (mFlags & NS_DTD_FLAG_HAS_OPEN_BODY) { - result = OpenContainer(theNode, theChildTag); - isTokenHandled=true; - } - break; - - case eHTMLTag_head: - mFlags |= NS_DTD_FLAG_HAS_EXPLICIT_HEAD; - - if (mFlags & NS_DTD_FLAG_HAS_MAIN_CONTAINER) { - HandleOmittedTag(aToken, theChildTag, theParent, theNode); - isTokenHandled = true; - } - break; - - default: - break; - } - } - - bool isExclusive = false; - theHeadIsParent = nsHTMLElement::IsChildOfHead(theChildTag, isExclusive); - - switch (theChildTag) { - case eHTMLTag_area: - if (!mOpenMapCount) { - isTokenHandled = true; - } - - if (mOpenMapCount > 0 && mSink) { - result = mSink->AddLeaf(*theNode); - isTokenHandled = true; - } - - break; - - case eHTMLTag_image: - aToken->SetTypeID(theChildTag = eHTMLTag_img); - break; - - case eHTMLTag_keygen: - result = HandleKeyGen(theNode); - isTokenHandled = true; - break; - - case eHTMLTag_script: - // Script isn't really exclusively in the head. However, we treat it - // as such to make sure that we don't pull scripts outside the head - // into the body. - // XXX Where does the script go in a frameset document? - isExclusive = !(mFlags & NS_DTD_FLAG_HAD_BODY); - break; - - default:; - } - - if (!isTokenHandled) { - bool prefersBody = - gHTMLElements[theChildTag].HasSpecialProperty(kPreferBody); - - // If this tag prefers to be in the head (when neither the head nor the - // body have been explicitly opened) then check that we haven't seen the - // body (true until the <body> tag has really been seen). Otherwise, - // check if the head has been explicitly opened. See bug 307122. - theHeadIsParent = theHeadIsParent && - (isExclusive || - (prefersBody - ? (mFlags & NS_DTD_FLAG_HAS_EXPLICIT_HEAD) && - (mFlags & NS_DTD_FLAG_HAS_OPEN_HEAD) - : !(mFlags & NS_DTD_FLAG_HAS_MAIN_CONTAINER))); - - if (theHeadIsParent) { - // These tokens prefer to be in the head. - result = AddHeadContent(theNode); - } else { - result = HandleDefaultStartToken(aToken, theChildTag, theNode); - } - } - - // Now do any post processing necessary on the tag... - if (NS_OK == result) { - DidHandleStartTag(*theNode, theChildTag); - } - } - } - - if (kHierarchyTooDeep == result) { - // Reset this error to ok; all that happens here is that given inline tag - // gets dropped because the stack is too deep. Don't terminate parsing. - result = NS_OK; - } - - IF_FREE(theNode, &mNodeAllocator); - return result; -} - -/** - * Call this to see if you have a closeable peer on the stack that - * is ABOVE one of its root tags. - * - * @update gess 4/11/99 - * @param aRootTagList -- list of root tags for aTag - * @param aTag -- tag to test for containership - * @return true if given tag can contain other tags - */ -static bool -HasCloseablePeerAboveRoot(const TagList& aRootTagList, nsDTDContext& aContext, - eHTMLTags aTag, bool anEndTag) -{ - int32_t theRootIndex = LastOf(aContext, aRootTagList); - const TagList* theCloseTags = anEndTag - ? gHTMLElements[aTag].GetAutoCloseEndTags() - : gHTMLElements[aTag].GetAutoCloseStartTags(); - int32_t theChildIndex = -1; - - if (theCloseTags) { - theChildIndex=LastOf(aContext, *theCloseTags); - } else if (anEndTag || !gHTMLElements[aTag].CanContainSelf()) { - theChildIndex = aContext.LastOf(aTag); - } - - // I changed this to theRootIndex<=theChildIndex so to handle this case: - // <SELECT><OPTGROUP>...</OPTGROUP> - return theRootIndex<=theChildIndex; -} - - -/** - * This method is called to determine whether or not an END tag - * can be autoclosed. This means that based on the current - * context, the stack should be closed to the nearest matching - * tag. - * - * @param aTag -- tag enum of child to be tested - * @return true if autoclosure should occur - */ -static eHTMLTags -FindAutoCloseTargetForEndTag(eHTMLTags aCurrentTag, nsDTDContext& aContext, - nsDTDMode aMode) -{ - int theTopIndex = aContext.GetCount(); - eHTMLTags thePrevTag = aContext.Last(); - - if (nsHTMLElement::IsContainer(aCurrentTag)) { - int32_t theChildIndex = - nsHTMLElement::GetIndexOfChildOrSynonym(aContext, aCurrentTag); - - if (kNotFound < theChildIndex) { - if (thePrevTag == aContext[theChildIndex]) { - return aContext[theChildIndex]; - } - - if (nsHTMLElement::IsBlockCloser(aCurrentTag)) { - /* - * Here's the algorithm: - * Our here is sitting at aChildIndex. There are other tags above it - * on the stack. We have to try to close them out, but we may encounter - * one that can block us. The way to tell is by comparing each tag on - * the stack against our closeTag and rootTag list. - * - * For each tag above our hero on the stack, ask 3 questions: - * 1. Is it in the closeTag list? If so, the we can skip over it - * 2. Is it in the rootTag list? If so, then we're gated by it - * 3. Otherwise its non-specified and we simply presume we can close it. - */ - const TagList* theCloseTags = - gHTMLElements[aCurrentTag].GetAutoCloseEndTags(); - const TagList* theRootTags = - gHTMLElements[aCurrentTag].GetEndRootTags(); - - if (theCloseTags) { - // At a mininimum, this code is needed for H1..H6 - while (theChildIndex < --theTopIndex) { - eHTMLTags theNextTag = aContext[theTopIndex]; - if (!FindTagInSet(theNextTag, theCloseTags->mTags, - theCloseTags->mCount) && - FindTagInSet(theNextTag, theRootTags->mTags, - theRootTags->mCount)) { - // We encountered a tag in root list so fail (we're gated). - return eHTMLTag_unknown; - } - - // Otherwise, presume it's something we can simply ignore and - // continue searching. - } - - eHTMLTags theTarget = aContext.TagAt(theChildIndex); - if (aCurrentTag != theTarget) { - aCurrentTag = theTarget; - } - // If you make it here, we're ungated and found a target! - return aCurrentTag; - } else if (theRootTags) { - // Since we didn't find any close tags, see if there is an instance of - // aCurrentTag above the stack from the roottag. - if (HasCloseablePeerAboveRoot(*theRootTags, aContext, aCurrentTag, - true)) { - return aCurrentTag; - } else { - return eHTMLTag_unknown; - } - } - } else { - // Ok, a much more sensible approach for non-block closers; use the tag - // group to determine closure: For example: %phrasal closes %phrasal, - // %fontstyle and %special - return gHTMLElements[aCurrentTag].GetCloseTargetForEndTag(aContext, - theChildIndex, - aMode); - } - } - } - - return eHTMLTag_unknown; -} - -static void -StripWSFollowingTag(eHTMLTags aChildTag, nsITokenizer* aTokenizer, - nsTokenAllocator* aTokenAllocator, int32_t* aNewlineCount) -{ - if (!aTokenizer || !aTokenAllocator) { - return; - } - - CToken* theToken = aTokenizer->PeekToken(); - - int32_t newlineCount = 0; - while (theToken) { - eHTMLTokenTypes theType = eHTMLTokenTypes(theToken->GetTokenType()); - - switch(theType) { - case eToken_newline: - case eToken_whitespace: - theToken = aTokenizer->PopToken(); - newlineCount += theToken->GetNewlineCount(); - IF_FREE(theToken, aTokenAllocator); - - theToken = aTokenizer->PeekToken(); - break; - - default: - theToken = nullptr; - break; - } - } - - if (aNewlineCount) { - *aNewlineCount += newlineCount; - } -} - -/** - * This method gets called when an end token has been - * encountered in the parse process. If the end tag matches - * the start tag on the stack, then simply close it. Otherwise, - * we have a erroneous state condition. This can be because we - * have a close tag with no prior open tag (user error) or because - * we screwed something up in the parse process. I'm not sure - * yet how to tell the difference. - * - * @param aToken -- next (start) token to be handled - * @return true if all went well; false if error occurred - */ -nsresult -CNavDTD::HandleEndToken(CToken* aToken) -{ - NS_PRECONDITION(nullptr != aToken, kNullToken); - - nsresult result = NS_OK; - eHTMLTags theChildTag = (eHTMLTags)aToken->GetTypeID(); - - // Begin by dumping any attributes (bug 143512) - CollectAttributes(nullptr, theChildTag, aToken->GetAttributeCount()); - - switch (theChildTag) { - case eHTMLTag_link: - case eHTMLTag_meta: - break; - - case eHTMLTag_head: - StripWSFollowingTag(theChildTag, mTokenizer, mTokenAllocator, - !mCountLines ? nullptr : &mLineNumber); - if (mBodyContext->LastOf(eHTMLTag_head) != kNotFound) { - result = CloseContainersTo(eHTMLTag_head, false); - } - mFlags &= ~NS_DTD_FLAG_HAS_EXPLICIT_HEAD; - break; - - case eHTMLTag_form: - result = CloseContainer(eHTMLTag_form, false); - break; - - case eHTMLTag_br: - { - // This is special NAV-QUIRKS code that allows users to use </BR>, even - // though that isn't a legitimate tag. - if (eDTDMode_quirks == mDTDMode) { - // Use recycler and pass the token thro' HandleToken() to fix bugs - // like 32782. - CToken* theToken = mTokenAllocator->CreateTokenOfType(eToken_start, - theChildTag); - result = HandleToken(theToken); - } - } - break; - - case eHTMLTag_body: - case eHTMLTag_html: - StripWSFollowingTag(theChildTag, mTokenizer, mTokenAllocator, - !mCountLines ? nullptr : &mLineNumber); - break; - - case eHTMLTag_script: - // Note: we don't fall through to the default case because - // CloseContainersTo() has the bad habit of closing tags that are opened - // by document.write(). Fortunately, the tokenizer guarantees that no - // actual tags appear between <script> and </script> so we won't be - // closing the wrong tag. - if (mBodyContext->Last() != eHTMLTag_script) { - // Except if we're here, then there's probably a stray script tag. - NS_ASSERTION(mBodyContext->LastOf(eHTMLTag_script) == kNotFound, - "Mishandling scripts in CNavDTD"); - break; - } - - mBodyContext->Pop(); - result = CloseContainer(eHTMLTag_script, aToken->IsInError()); - break; - - default: - { - // Now check to see if this token should be omitted, or - // if it's gated from closing by the presence of another tag. - if (gHTMLElements[theChildTag].CanOmitEndTag()) { - PopStyle(theChildTag); - } else { - eHTMLTags theParentTag = mBodyContext->Last(); - - // First open transient styles, so that we see any autoclosed style - // tags. - if (nsHTMLElement::IsResidualStyleTag(theChildTag)) { - result = OpenTransientStyles(theChildTag); - if (NS_FAILED(result)) { - return result; - } - } - - if (kNotFound == - nsHTMLElement::GetIndexOfChildOrSynonym(*mBodyContext, - theChildTag)) { - // Ref: bug 30487 - // Make sure that we don't cross boundaries, of certain elements, - // to close stylistic information. - // <font face="helvetica"><table><tr><td></font></td></tr></table> some text... - // In the above ex. the orphaned FONT tag, inside TD, should cross - // TD boundary to close the FONT tag above TABLE. - static eHTMLTags gBarriers[] = { - eHTMLTag_thead, eHTMLTag_tbody, eHTMLTag_tfoot, eHTMLTag_table - }; - - if (!FindTagInSet(theParentTag, gBarriers, - ArrayLength(gBarriers)) && - nsHTMLElement::IsResidualStyleTag(theChildTag)) { - // Fix bug 77746 - mBodyContext->RemoveStyle(theChildTag); - } - - // If the bit kHandleStrayTag is set then we automatically open up a - // matching start tag (compatibility). Currently this bit is set on - // P tag. This also fixes Bug: 22623 - if (gHTMLElements[theChildTag].HasSpecialProperty(kHandleStrayTag) && - mDTDMode != eDTDMode_full_standards && - mDTDMode != eDTDMode_almost_standards) { - // Oh boy!! we found a "stray" tag. Nav4.x and IE introduce line - // break in such cases. So, let's simulate that effect for - // compatibility. - // Ex. <html><body>Hello</P>There</body></html> - int32_t theParentContains = -1; - if (!CanOmit(theParentTag, theChildTag, theParentContains)) { - CToken* theStartToken = - mTokenAllocator->CreateTokenOfType(eToken_start, theChildTag); - NS_ENSURE_TRUE(theStartToken, NS_ERROR_OUT_OF_MEMORY); - - // This check for NS_DTD_FLAG_IN_MISPLACED_CONTENT was added - // to fix bug 142965. - if (!(mFlags & NS_DTD_FLAG_IN_MISPLACED_CONTENT)) { - // We're not handling misplaced content right now, just push - // these new tokens back on the stack and handle them in the - // regular flow of HandleToken. - IF_HOLD(aToken); - mTokenizer->PushTokenFront(aToken); - mTokenizer->PushTokenFront(theStartToken); - } else { - // Oops, we're in misplaced content. Handle these tokens - // directly instead of trying to push them onto the tokenizer - // stack. - result = HandleToken(theStartToken); - NS_ENSURE_SUCCESS(result, result); - - IF_HOLD(aToken); - result = HandleToken(aToken); - } - } - } - return result; - } - if (result == NS_OK) { - eHTMLTags theTarget = - FindAutoCloseTargetForEndTag(theChildTag, *mBodyContext, - mDTDMode); - if (eHTMLTag_unknown != theTarget) { - result = CloseContainersTo(theTarget, false); - } - } - } - } - break; - } - - return result; -} - -/** - * This method will be triggered when the end of a table is - * encountered. Its primary purpose is to process all the - * bad-contents pertaining a particular table. The position - * of the table is the token bank ID. - * - * @update harishd 03/24/99 - * @param aTag - This ought to be a table tag - * - */ -nsresult -CNavDTD::HandleSavedTokens(int32_t anIndex) -{ - NS_PRECONDITION(mBodyContext != nullptr && mBodyContext->GetCount() > 0, "invalid context"); - - nsresult result = NS_OK; - - if (mSink && (anIndex > kNotFound)) { - int32_t theBadTokenCount = mMisplacedContent.GetSize(); - - if (theBadTokenCount > 0) { - mFlags |= NS_DTD_FLAG_IN_MISPLACED_CONTENT; - - if (!mTempContext && !(mTempContext = new nsDTDContext())) { - return NS_ERROR_OUT_OF_MEMORY; - } - - CToken* theToken; - eHTMLTags theTag; - int32_t attrCount; - int32_t theTopIndex = anIndex + 1; - int32_t theTagCount = mBodyContext->GetCount(); - - // Pause the main context and switch to the new context. - result = mSink->BeginContext(anIndex); - - NS_ENSURE_SUCCESS(result, result); - - // The body context should contain contents only upto the marked position. - mBodyContext->MoveEntries(*mTempContext, theTagCount - theTopIndex); - - // Now flush out all the bad contents. - while (theBadTokenCount-- > 0){ - theToken = (CToken*)mMisplacedContent.PopFront(); - if (theToken) { - theTag = (eHTMLTags)theToken->GetTypeID(); - attrCount = theToken->GetAttributeCount(); - // Put back attributes, which once got popped out, into the - // tokenizer. Make sure we preserve their ordering, however! - // XXXbz would it be faster to get the tokens out with ObjectAt and - // put them in the tokenizer and then PopFront them all from - // mMisplacedContent? - nsDeque temp; - for (int32_t j = 0; j < attrCount; ++j) { - CToken* theAttrToken = (CToken*)mMisplacedContent.PopFront(); - if (theAttrToken) { - temp.Push(theAttrToken); - } - theBadTokenCount--; - } - mTokenizer->PrependTokens(temp); - - if (eToken_end == theToken->GetTokenType()) { - // Ref: Bug 25202 - // Make sure that the BeginContext() is ended only by the call to - // EndContext(). Ex: <center><table><a></center>. - // In the Ex. above </center> should not close <center> above table. - // Doing so will cause the current context to get closed prematurely. - eHTMLTags closed = FindAutoCloseTargetForEndTag(theTag, *mBodyContext, - mDTDMode); - int32_t theIndex = closed != eHTMLTag_unknown - ? mBodyContext->LastOf(closed) - : kNotFound; - - if (theIndex != kNotFound && - theIndex <= mBodyContext->mContextTopIndex) { - IF_FREE(theToken, mTokenAllocator); - continue; - } - } - - // XXX This should go away, with this call, it becomes extremely - // difficult to handle misplaced style and link tags, since it's hard - // to propagate the block return all the way up and then re-enter this - // method. - result = HandleToken(theToken); - } - } - - if (theTopIndex != mBodyContext->GetCount()) { - // CloseContainersTo does not close any forms we might have opened while - // handling saved tokens, because the parser does not track forms on its - // mBodyContext stack. - CloseContainersTo(theTopIndex, mBodyContext->TagAt(theTopIndex), - true); - } - - // Bad-contents were successfully processed. Now, itz time to get - // back to the original body context state. - mTempContext->MoveEntries(*mBodyContext, theTagCount - theTopIndex); - - // Terminate the new context and switch back to the main context - mSink->EndContext(anIndex); - - mFlags &= ~NS_DTD_FLAG_IN_MISPLACED_CONTENT; - } - } - return result; -} - - -/** - * This method gets called when an entity token has been - * encountered in the parse process. - * - * @update gess 3/25/98 - * @param aToken -- next (start) token to be handled - * @return true if all went well; false if error occurred - */ -nsresult -CNavDTD::HandleEntityToken(CToken* aToken) -{ - NS_PRECONDITION(nullptr != aToken, kNullToken); - - nsresult result = NS_OK; - - const nsSubstring& theStr = aToken->GetStringValue(); - - if (kHashsign != theStr.First() && - -1 == nsHTMLEntities::EntityToUnicode(theStr)) { - // If you're here we have a bogus entity. - // Convert it into a text token. - CToken *theToken; - - nsAutoString entityName; - entityName.AssignLiteral("&"); - entityName.Append(theStr); - theToken = mTokenAllocator->CreateTokenOfType(eToken_text, eHTMLTag_text, - entityName); - NS_ENSURE_TRUE(theToken, NS_ERROR_OUT_OF_MEMORY); - - // theToken should get recycled automagically... - return HandleToken(theToken); - } - - eHTMLTags theParentTag = mBodyContext->Last(); - nsCParserNode* theNode = mNodeAllocator.CreateNode(aToken, mTokenAllocator); - NS_ENSURE_TRUE(theNode, NS_ERROR_OUT_OF_MEMORY); - - int32_t theParentContains = -1; - if (CanOmit(theParentTag, eHTMLTag_entity, theParentContains)) { - eHTMLTags theCurrTag = (eHTMLTags)aToken->GetTypeID(); - HandleOmittedTag(aToken, theCurrTag, theParentTag, theNode); - } else { - result = AddLeaf(theNode); - } - IF_FREE(theNode, &mNodeAllocator); - return result; -} - -/** - * This method gets called when a comment token has been - * encountered in the parse process. After making sure - * we're somewhere in the body, we handle the comment - * in the same code that we use for text. - * - * @update gess 3/25/98 - * @param aToken -- next (start) token to be handled - * @return true if all went well; false if error occurred - */ -nsresult -CNavDTD::HandleCommentToken(CToken* aToken) -{ - NS_PRECONDITION(nullptr != aToken, kNullToken); - return NS_OK; -} - - -/** - * This method gets called when an attribute token has been - * encountered in the parse process. This is an error, since - * all attributes should have been accounted for in the prior - * start or end tokens - * - * @update gess 3/25/98 - * @param aToken -- next (start) token to be handled - * @return true if all went well; false if error occurred - */ -nsresult -CNavDTD::HandleAttributeToken(CToken* aToken) -{ - NS_ERROR("attribute encountered -- this shouldn't happen."); - return NS_OK; -} - -/** - * This method gets called when an "instruction" token has been - * encountered in the parse process. - * - * @update gess 3/25/98 - * @param aToken -- next (start) token to be handled - * @return true if all went well; false if error occurred - */ -nsresult -CNavDTD::HandleProcessingInstructionToken(CToken* aToken) -{ - NS_PRECONDITION(nullptr != aToken, kNullToken); - return NS_OK; -} - -/** - * This method gets called when a DOCTYPE token has been - * encountered in the parse process. - * - * @update harishd 09/02/99 - * @param aToken -- The very first token to be handled - * @return true if all went well; false if error occurred - */ -nsresult -CNavDTD::HandleDocTypeDeclToken(CToken* aToken) -{ - NS_PRECONDITION(nullptr != aToken, kNullToken); - - CDoctypeDeclToken* theToken = static_cast<CDoctypeDeclToken*>(aToken); - nsAutoString docTypeStr(theToken->GetStringValue()); - // XXX Doesn't this count the newlines twice? - if (mCountLines) { - mLineNumber += docTypeStr.CountChar(kNewLine); - } - - int32_t len = docTypeStr.Length(); - int32_t pos = docTypeStr.RFindChar(kGreaterThan); - if (pos != kNotFound) { - // First remove '>' from the end. - docTypeStr.Cut(pos, len - pos); - } - - // Now remove "<!" from the begining - docTypeStr.Cut(0, 2); - theToken->SetStringValue(docTypeStr); - return NS_OK; -} - -/** - * Retrieve the attributes for this node, and add then into - * the node. - * - * @update gess4/22/98 - * @param aNode is the node you want to collect attributes for - * @param aCount is the # of attributes you're expecting - * @return error code (should be 0) - */ -nsresult -CNavDTD::CollectAttributes(nsIParserNode *aNode, eHTMLTags aTag, int32_t aCount) -{ - int attr = 0; - nsresult result = NS_OK; - int theAvailTokenCount = mTokenizer->GetCount(); - - if (aCount <= theAvailTokenCount) { - CToken* theToken; - for (attr = 0; attr < aCount; ++attr) { - theToken = mTokenizer->PopToken(); - if (theToken) { - eHTMLTokenTypes theType = eHTMLTokenTypes(theToken->GetTokenType()); - if (theType != eToken_attribute) { - // If you're here then it means that the token does not - // belong to this node. Put the token back into the tokenizer - // and let it go thro' the regular path. Bug: 59189. - mTokenizer->PushTokenFront(theToken); - break; - } - - if (mCountLines) { - mLineNumber += theToken->GetNewlineCount(); - } - - if (aNode) { - // If the key is empty, the attribute is unusable, so we should not - // add it to the node. - if (!((CAttributeToken*)theToken)->GetKey().IsEmpty()) { - aNode->AddAttribute(theToken); - } else { - IF_FREE(theToken, mTokenAllocator); - } - } else { - IF_FREE(theToken, mTokenAllocator); - } - } - } - } else { - result = kEOF; - } - 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 true if parent can contain child - */ -NS_IMETHODIMP_(bool) -CNavDTD::CanContain(int32_t aParent, int32_t aChild) const -{ - bool result = gHTMLElements[aParent].CanContain((eHTMLTags)aChild, mDTDMode); - - if (eHTMLTag_nobr == aChild && - IsInlineElement(aParent, aParent) && - HasOpenContainer(eHTMLTag_nobr)) { - return false; - } - - return result; -} - -/** - * This method is called to determine whether or not - * the given childtag is a block element. - * - * @update gess 6June2000 - * @param aChildID -- tag id of child - * @param aParentID -- tag id of parent (or eHTMLTag_unknown) - * @return true if this tag is a block tag - */ -bool -CNavDTD::IsBlockElement(int32_t aTagID, int32_t aParentID) const -{ - eHTMLTags theTag = (eHTMLTags)aTagID; - - return (theTag > eHTMLTag_unknown && theTag < eHTMLTag_userdefined) && - (gHTMLElements[theTag].IsMemberOf(kBlock) || - gHTMLElements[theTag].IsMemberOf(kBlockEntity) || - gHTMLElements[theTag].IsMemberOf(kHeading) || - gHTMLElements[theTag].IsMemberOf(kPreformatted) || - gHTMLElements[theTag].IsMemberOf(kList)); -} - -/** - * This method is called to determine whether or not - * the given childtag is an inline element. - * - * @update gess 6June2000 - * @param aChildID -- tag id of child - * @param aParentID -- tag id of parent (or eHTMLTag_unknown) - * @return true if this tag is an inline tag - */ -bool -CNavDTD::IsInlineElement(int32_t aTagID, int32_t aParentID) const -{ - eHTMLTags theTag = (eHTMLTags)aTagID; - - return (theTag > eHTMLTag_unknown && theTag < eHTMLTag_userdefined) && - (gHTMLElements[theTag].IsMemberOf(kInlineEntity) || - gHTMLElements[theTag].IsMemberOf(kFontStyle) || - gHTMLElements[theTag].IsMemberOf(kPhrase) || - gHTMLElements[theTag].IsMemberOf(kSpecial) || - gHTMLElements[theTag].IsMemberOf(kFormControl)); -} - -/** - * This method is called to determine whether or not - * the necessary intermediate tags should be propagated - * between the given parent and given child. - * - * @update gess 4/8/98 - * @param aParent -- tag enum of parent container - * @param aChild -- tag enum of child container - * @return true if propagation should occur - */ -bool -CNavDTD::CanPropagate(eHTMLTags aParent, eHTMLTags aChild, - int32_t aParentContains) -{ - bool result = false; - if (aParentContains == -1) { - aParentContains = CanContain(aParent, aChild); - } - - if (aParent == aChild) { - return result; - } - - if (nsHTMLElement::IsContainer(aChild)) { - mScratch.Truncate(); - if (!gHTMLElements[aChild].HasSpecialProperty(kNoPropagate)) { - if (nsHTMLElement::IsBlockParent(aParent) || - gHTMLElements[aParent].GetSpecialChildren()) { - result = ForwardPropagate(mScratch, aParent, aChild); - if (!result) { - if (eHTMLTag_unknown != aParent) { - result = BackwardPropagate(mScratch, aParent, aChild); - } else { - result = BackwardPropagate(mScratch, eHTMLTag_html, aChild); - } - } - } - } - if (mScratch.Length() - 1 > gHTMLElements[aParent].mPropagateRange) { - result = false; - } - } else { - result = !!aParentContains; - } - - - return result; -} - - -/** - * This method gets called to determine whether a given - * tag can be omitted from opening. Most cannot. - * - * @param aParent - * @param aChild - * @param aParentContains - * @return true if given tag can contain other tags - */ -bool -CNavDTD::CanOmit(eHTMLTags aParent, eHTMLTags aChild, int32_t& aParentContains) -{ - eHTMLTags theAncestor = gHTMLElements[aChild].mExcludingAncestor; - if (eHTMLTag_unknown != theAncestor && HasOpenContainer(theAncestor)) { - return true; - } - - theAncestor = gHTMLElements[aChild].mRequiredAncestor; - if (eHTMLTag_unknown != theAncestor) { - // If there's a required ancestor, we only omit if it isn't open and we - // can't get to it through propagation. - return !HasOpenContainer(theAncestor) && - !CanPropagate(aParent, aChild, aParentContains); - } - - if (gHTMLElements[aParent].CanExclude(aChild)) { - return true; - } - - // Now the obvious test: if the parent can contain the child, don't omit. - if (-1 == aParentContains) { - aParentContains = CanContain(aParent, aChild); - } - - if (aParentContains || aChild == aParent) { - return false; - } - - if (gHTMLElements[aParent].IsBlockEntity() && - nsHTMLElement::IsInlineEntity(aChild)) { - // Feel free to drop inlines that a block doesn't contain. - return true; - } - - if (gHTMLElements[aParent].HasSpecialProperty(kBadContentWatch)) { - // We can only omit this child if it does not have the kBadContentWatch - // special property. - return !gHTMLElements[aChild].HasSpecialProperty(kBadContentWatch); - } - - if (gHTMLElements[aParent].HasSpecialProperty(kSaveMisplaced)) { - return true; - } - - if (aParent == eHTMLTag_body) { - // There are very few tags that the body does not contain. If we get here - // the best thing to do is just drop them. - return true; - } - - return false; -} - -/** - * This method gets called to determine whether a given - * tag is itself a container - * - * @update gess 4/8/98 - * @param aTag -- tag to test as a container - * @return true if given tag can contain other tags - */ NS_IMETHODIMP_(bool) CNavDTD::IsContainer(int32_t aTag) const { - return nsHTMLElement::IsContainer((eHTMLTags)aTag); -} - - -bool -CNavDTD::ForwardPropagate(nsString& aSequence, eHTMLTags aParent, - eHTMLTags aChild) -{ - bool result = false; - - switch(aParent) { - case eHTMLTag_table: - if (eHTMLTag_tr == aChild || eHTMLTag_td == aChild) { - return BackwardPropagate(aSequence, aParent, aChild); - } - // Otherwise, intentionally fall through... - - case eHTMLTag_tr: - if (CanContain(eHTMLTag_td, aChild)) { - aSequence.Append((PRUnichar)eHTMLTag_td); - result = BackwardPropagate(aSequence, aParent, eHTMLTag_td); - } - break; - - default: - break; - } - - return result; -} - -bool -CNavDTD::BackwardPropagate(nsString& aSequence, eHTMLTags aParent, - eHTMLTags aChild) const -{ - eHTMLTags theParent = aParent; - - do { - const TagList* theRootTags = gHTMLElements[aChild].GetRootTags(); - if (!theRootTags) { - break; - } - - theParent = theRootTags->mTags[0]; - NS_ASSERTION(CanContain(theParent, aChild), - "Children must be contained by their root tags"); - - aChild = theParent; - aSequence.Append((PRUnichar)theParent); - } while (theParent != eHTMLTag_unknown && theParent != aParent); - - return aParent == theParent; -} - -bool CNavDTD::HasOpenContainer(eHTMLTags aContainer) const -{ - switch (aContainer) { - case eHTMLTag_form: - return !(~mFlags & NS_DTD_FLAG_HAS_OPEN_FORM); - case eHTMLTag_map: - return mOpenMapCount > 0; - default: - return mBodyContext->HasOpenContainer(aContainer); - } -} - -bool -CNavDTD::HasOpenContainer(const eHTMLTags aTagSet[], int32_t aCount) const -{ - int theIndex; - int theTopIndex = mBodyContext->GetCount() - 1; - - for (theIndex = theTopIndex; theIndex > 0; --theIndex) { - if (FindTagInSet((*mBodyContext)[theIndex], aTagSet, aCount)) { - return true; - } - } - + MOZ_CRASH("nobody calls this"); return false; } - -eHTMLTags -CNavDTD::GetTopNode() const -{ - return mBodyContext->Last(); -} - -/** - * It is with great trepidation that I offer this method (privately of course). - * The gets called whenever a container gets opened. This methods job is to - * take a look at the (transient) style stack, and open any style containers that - * are there. Of course, we shouldn't bother to open styles that are incompatible - * with our parent container. - * - * @update gess6/4/98 - * @param tag of the container just opened - * @return 0 (for now) - */ -nsresult -CNavDTD::OpenTransientStyles(eHTMLTags aChildTag, bool aCloseInvalid) -{ - nsresult result = NS_OK; - - // No need to open transient styles in head context - Fix for 41427 - if ((mFlags & NS_DTD_FLAG_ENABLE_RESIDUAL_STYLE) && - eHTMLTag_newline != aChildTag && - !(mFlags & NS_DTD_FLAG_HAS_OPEN_HEAD)) { - if (CanContain(eHTMLTag_font, aChildTag)) { - uint32_t theCount = mBodyContext->GetCount(); - uint32_t theLevel = theCount; - - // This first loop is used to determine how far up the containment - // hierarchy we go looking for residual styles. - while (1 < theLevel) { - eHTMLTags theParentTag = mBodyContext->TagAt(--theLevel); - if (gHTMLElements[theParentTag].HasSpecialProperty(kNoStyleLeaksIn)) { - break; - } - } - - mFlags &= ~NS_DTD_FLAG_ENABLE_RESIDUAL_STYLE; - for (; theLevel < theCount; ++theLevel) { - nsEntryStack* theStack = mBodyContext->GetStylesAt(theLevel); - if (theStack) { - // Don't open transient styles if it makes the stack deep, bug 58917. - if (theCount + theStack->mCount >= FONTSTYLE_IGNORE_DEPTH) { - break; - } - - int32_t sindex = 0; - - nsTagEntry *theEntry = theStack->mEntries; - bool isHeadingOpen = HasOpenTagOfType(kHeading, *mBodyContext); - for (sindex = 0; sindex < theStack->mCount; ++sindex) { - nsCParserNode* theNode = (nsCParserNode*)theEntry->mNode; - if (1 == theNode->mUseCount) { - eHTMLTags theNodeTag = (eHTMLTags)theNode->GetNodeType(); - if (gHTMLElements[theNodeTag].CanContain(aChildTag, mDTDMode)) { - // XXX The following comment is entirely incoherent. - // We do this too, because this entry differs from the new one - // we're pushing. - theEntry->mParent = theStack; - if (isHeadingOpen) { - // Bug 77352 - // The style system needs to identify residual style tags - // within heading tags so that heading tags' size can take - // precedence over the residual style tags' size info.. - // *Note: Make sure that this attribute is transient since it - // should not get carried over to cases other than heading. - CAttributeToken theAttrToken(NS_LITERAL_STRING("_moz-rs-heading"), - EmptyString()); - theNode->AddAttribute(&theAttrToken); - result = OpenContainer(theNode, theNodeTag, theStack); - theNode->PopAttributeToken(); - } else { - result = OpenContainer(theNode, theNodeTag, theStack); - } - } else if (aCloseInvalid) { - // If the node tag can't contain the child tag, then remove the - // child tag from the style stack - nsCParserNode* node = theStack->Remove(sindex, theNodeTag); - IF_FREE(node, &mNodeAllocator); - --theEntry; - } - } - ++theEntry; - } - } - } - mFlags |= NS_DTD_FLAG_ENABLE_RESIDUAL_STYLE; - } - } - - return result; -} - -/** - * This method gets called when an explicit style close-tag is encountered. - * It results in the style tag id being popped from our internal style stack. - * - * @update gess6/4/98 - * @param - * @return 0 if all went well (which it always does) - */ -void -CNavDTD::PopStyle(eHTMLTags aTag) -{ - if ((mFlags & NS_DTD_FLAG_ENABLE_RESIDUAL_STYLE) && - nsHTMLElement::IsResidualStyleTag(aTag)) { - nsCParserNode* node = mBodyContext->PopStyle(aTag); - IF_FREE(node, &mNodeAllocator); - } -} - - -/** - * 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/22/98 - * @param aNode -- next node to be added to model - */ -nsresult -CNavDTD::OpenHTML(const nsCParserNode *aNode) -{ - NS_PRECONDITION(mBodyContext->GetCount() >= 0, kInvalidTagStackPos); - - nsresult result = mSink ? mSink->OpenContainer(*aNode) : NS_OK; - - // Don't push more than one HTML tag into the stack. - if (mBodyContext->GetCount() == 0) { - mBodyContext->Push(const_cast<nsCParserNode*>(aNode), 0, false); - } - - 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 - */ -nsresult -CNavDTD::OpenBody(const nsCParserNode *aNode) -{ - NS_PRECONDITION(mBodyContext->GetCount() >= 0, kInvalidTagStackPos); - - nsresult result = NS_OK; - - if (!(mFlags & NS_DTD_FLAG_HAD_FRAMESET)) { - mFlags |= NS_DTD_FLAG_HAD_BODY; - - // Make sure the head is closed by the time the body is opened. - CloseContainer(eHTMLTag_head, false); - - // Now we can open the body. - result = mSink ? mSink->OpenContainer(*aNode) : NS_OK; - - if (!HasOpenContainer(eHTMLTag_body)) { - mBodyContext->Push(const_cast<nsCParserNode*>(aNode), 0, false); - mTokenizer->PrependTokens(mMisplacedContent); - } - } - - 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 - * @param aClosedByStartTag -- ONLY TRUE if the container is being closed by opening of another container. - * @return TRUE if ok, FALSE if error - */ -nsresult -CNavDTD::OpenContainer(const nsCParserNode *aNode, - eHTMLTags aTag, - nsEntryStack* aStyleStack) -{ - NS_PRECONDITION(mBodyContext->GetCount() >= 0, kInvalidTagStackPos); - - nsresult result = NS_OK; - bool done = true; - bool rs_tag = nsHTMLElement::IsResidualStyleTag(aTag); - // We need to open transient styles to encompass the <li> so that the bullets - // inherit the proper colors. - bool li_tag = aTag == eHTMLTag_li; - - if (rs_tag || li_tag) { - /* - * Here's an interesting problem: - * - * If there's an <a> on the RS-stack, and you're trying to open - * another <a>, the one on the RS-stack should be discarded. - * - * I'm updating OpenTransientStyles to throw old <a>'s away. - */ - OpenTransientStyles(aTag, !li_tag); - } - - switch (aTag) { - case eHTMLTag_html: - result = OpenHTML(aNode); - break; - - case eHTMLTag_head: - if (!(mFlags & NS_DTD_FLAG_HAS_OPEN_HEAD)) { - mFlags |= NS_DTD_FLAG_HAS_OPEN_HEAD; - done = false; - } - break; - - case eHTMLTag_body: - { - eHTMLTags theParent = mBodyContext->Last(); - if (!gHTMLElements[aTag].IsSpecialParent(theParent)) { - mFlags |= NS_DTD_FLAG_HAS_OPEN_BODY; - result = OpenBody(aNode); - } else { - done = false; - } - } - break; - - case eHTMLTag_map: - ++mOpenMapCount; - done = false; - break; - - case eHTMLTag_form: - // Discard nested forms - bug 72639 - if (!(mFlags & NS_DTD_FLAG_HAS_OPEN_FORM)) { - mFlags |= NS_DTD_FLAG_HAS_OPEN_FORM; - result = mSink ? mSink->OpenContainer(*aNode) : NS_OK; - } - break; - - case eHTMLTag_frameset: - // Make sure that the head is closed before we try to open this frameset. - CloseContainer(eHTMLTag_head, false); - - // Now that the head is closed, continue on with opening this frameset. - mFlags |= NS_DTD_FLAG_HAD_FRAMESET; - done = false; - break; - - case eHTMLTag_noembed: - // <noembed> is unconditionally alternate content. - done = false; - mFlags |= NS_DTD_FLAG_ALTERNATE_CONTENT; - break; - - case eHTMLTag_noscript: - // We want to make sure that OpenContainer gets called below since we're - // not doing it here - done = false; - - if (mFlags & NS_IPARSER_FLAG_SCRIPT_ENABLED) { - // XXX This flag doesn't currently do anything (and would be - // insufficient if it did). - mFlags |= NS_DTD_FLAG_ALTERNATE_CONTENT; - } - break; - - case eHTMLTag_iframe: // Bug 84491 - case eHTMLTag_noframes: - done = false; - if (mFlags & NS_IPARSER_FLAG_FRAMES_ENABLED) { - mFlags |= NS_DTD_FLAG_ALTERNATE_CONTENT; - } - break; - - default: - done = false; - break; - } - - if (!done) { - - result = mSink ? mSink->OpenContainer(*aNode) : NS_OK; - - // For residual style tags rs_tag will be true and hence - // the body context will hold an extra reference to the node. - mBodyContext->Push(const_cast<nsCParserNode*>(aNode), aStyleStack, rs_tag); - } - - return result; -} - -nsresult -CNavDTD::CloseResidualStyleTags(const eHTMLTags aTag, - bool aClosedByStartTag) -{ - const int32_t count = mBodyContext->GetCount(); - int32_t pos = count; - while (nsHTMLElement::IsResidualStyleTag(mBodyContext->TagAt(pos - 1))) - --pos; - if (pos < count) - return CloseContainersTo(pos, aTag, aClosedByStartTag); - return NS_OK; -} - -/** - * 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 aTag -- id of tag to be closed - * @return TRUE if ok, FALSE if error - */ -nsresult -CNavDTD::CloseContainer(const eHTMLTags aTag, bool aMalformed) -{ - nsresult result = NS_OK; - bool done = true; - - switch (aTag) { - case eHTMLTag_head: - if (mFlags & NS_DTD_FLAG_HAS_OPEN_HEAD) { - mFlags &= ~NS_DTD_FLAG_HAS_OPEN_HEAD; - if (mBodyContext->Last() == eHTMLTag_head) { - mBodyContext->Pop(); - } else { - // This else can happen because CloseContainer is called both directly - // and from CloseContainersTo. CloseContainersTo pops the current tag - // off of the stack before calling CloseContainer. - NS_ASSERTION(mBodyContext->LastOf(eHTMLTag_head) == kNotFound, - "Closing the wrong tag"); - } - done = false; - } - break; - - case eHTMLTag_map: - if (mOpenMapCount) { - mOpenMapCount--; - done = false; - } - break; - - case eHTMLTag_form: - if (mFlags & NS_DTD_FLAG_HAS_OPEN_FORM) { - mFlags &= ~NS_DTD_FLAG_HAS_OPEN_FORM; - done = false; - // If we neglect to close these tags, the sink will refuse to close the - // form because the form will not be on the top of the SinkContext stack. - // See HTMLContentSink::CloseForm. (XXX do this in other cases?) - CloseResidualStyleTags(eHTMLTag_form, false); - } - break; - - case eHTMLTag_iframe: - case eHTMLTag_noembed: - case eHTMLTag_noscript: - case eHTMLTag_noframes: - // Switch from alternate content state to regular state. - mFlags &= ~NS_DTD_FLAG_ALTERNATE_CONTENT; - - // falling thro' intentionally.... - default: - done = false; - } - - if (!done) { - - if (mSink) { - result = !aMalformed - ? mSink->CloseContainer(aTag) - : mSink->CloseMalformedContainer(aTag); - } - - // If we were dealing with a head container in the body, make sure to - // close the head context now, so that body content doesn't get sucked - // into the head. - if (mBodyContext->GetCount() == mHeadContainerPosition) { - mHeadContainerPosition = -1; - nsresult headresult = CloseContainer(eHTMLTag_head, false); - - // Note: we could be assigning NS_OK into NS_OK here, but that's ok. - // This test is to avoid a successful CloseHead result stomping over a - // request to block the parser. - if (NS_SUCCEEDED(result)) { - result = headresult; - } - } - } - - 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 anIndex - * @param aTag - * @param aClosedByStartTag -- if TRUE, then we're closing something because a start tag caused it - * @return TRUE if ok, FALSE if error - */ -nsresult -CNavDTD::CloseContainersTo(int32_t anIndex, eHTMLTags aTarget, - bool aClosedByStartTag) -{ - NS_PRECONDITION(mBodyContext->GetCount() > 0, kInvalidTagStackPos); - nsresult result = NS_OK; - - if (anIndex < mBodyContext->GetCount() && anIndex >= 0) { - int32_t count = 0; - while ((count = mBodyContext->GetCount()) > anIndex) { - nsEntryStack* theChildStyleStack = 0; - eHTMLTags theTag = mBodyContext->Last(); - nsCParserNode* theNode = mBodyContext->Pop(theChildStyleStack); - result = CloseContainer(theTag, false); - - bool theTagIsStyle = nsHTMLElement::IsResidualStyleTag(theTag); - // If the current tag cannot leak out then we shouldn't leak out of the target - Fix 40713 - bool theStyleDoesntLeakOut = gHTMLElements[theTag].HasSpecialProperty(kNoStyleLeaksOut); - if (!theStyleDoesntLeakOut) { - theStyleDoesntLeakOut = gHTMLElements[aTarget].HasSpecialProperty(kNoStyleLeaksOut); - } - - // Do not invoke residual style handling when dealing with - // alternate content. This fixed bug 25214. - if (theTagIsStyle && !(mFlags & NS_DTD_FLAG_ALTERNATE_CONTENT)) { - NS_ASSERTION(theNode, "residual style node should not be null"); - if (!theNode) { - if (theChildStyleStack) { - mBodyContext->PushStyles(theChildStyleStack); - } - return NS_OK; - } - - bool theTargetTagIsStyle = nsHTMLElement::IsResidualStyleTag(aTarget); - if (aClosedByStartTag) { - // Handle closure due to new start tag. - // The cases we're handing here: - // 1. <body><b><DIV> //<b> gets pushed onto <body>.mStyles. - // 2. <body><a>text<a> //in this case, the target matches, so don't push style - if (theNode->mUseCount == 0) { - if (theTag != aTarget) { - if (theChildStyleStack) { - theChildStyleStack->PushFront(theNode); - } else { - mBodyContext->PushStyle(theNode); - } - } - } else if (theTag == aTarget && !gHTMLElements[aTarget].CanContainSelf()) { - //here's a case we missed: <a><div>text<a>text</a></div> - //The <div> pushes the 1st <a> onto the rs-stack, then the 2nd <a> - //pops the 1st <a> from the rs-stack altogether. - nsCParserNode* node = mBodyContext->PopStyle(theTag); - IF_FREE(node, &mNodeAllocator); - } - - if (theChildStyleStack) { - mBodyContext->PushStyles(theChildStyleStack); - } - } else { - /* - * if you're here, then we're dealing with the closure of tags - * caused by a close tag (as opposed to an open tag). - * At a minimum, we should consider pushing residual styles up - * up the stack or popping and recycling displaced nodes. - * - * Known cases: - * 1. <body><b><div>text</DIV> - * Here the <b> will leak into <div> (see case given above), and - * when <div> closes the <b> is dropped since it's already residual. - * - * 2. <body><div><b>text</div> - * Here the <b> will leak out of the <div> and get pushed onto - * the RS stack for the <body>, since it originated in the <div>. - * - * 3. <body><span><b>text</span> - * In this case, the the <b> get's pushed onto the style stack. - * Later we deal with RS styles stored on the <span> - * - * 4. <body><span><b>text</i> - * Here we the <b>is closed by a (synonymous) style tag. - * In this case, the <b> is simply closed. - */ - if (theChildStyleStack) { - if (!theStyleDoesntLeakOut) { - if (theTag != aTarget) { - if (theNode->mUseCount == 0) { - theChildStyleStack->PushFront(theNode); - } - } else if (theNode->mUseCount == 1) { - // This fixes bug 30885,29626. - // Make sure that the node, which is about to - // get released does not stay on the style stack... - // Also be sure to remove the correct style off the - // style stack. - Ref. bug 94208. - // Ex <FONT><B><I></FONT><FONT></B></I></FONT> - // Make sure that </B> removes B off the style stack. - mBodyContext->RemoveStyle(theTag); - } - mBodyContext->PushStyles(theChildStyleStack); - } else{ - IF_DELETE(theChildStyleStack, &mNodeAllocator); - } - } else if (theNode->mUseCount == 0) { - // The old version of this only pushed if the targettag wasn't - // style. But that misses this case: <font><b>text</font>, where - // the b should leak. - if (aTarget != theTag) { - mBodyContext->PushStyle(theNode); - } - } else { - // Ah, at last, the final case. If you're here, then we just popped - // a style tag that got onto that tag stack from a stylestack - // somewhere. Pop it from the stylestack if the target is also a - // style tag. Make sure to remove the matching style. In the - // following example: - // <FONT><B><I></FONT><FONT color=red></B></I></FONT> - // make sure that </I> does not remove - // <FONT color=red> off the style stack. - bug 94208 - if (theTargetTagIsStyle && theTag == aTarget) { - mBodyContext->RemoveStyle(theTag); - } - } - } - } else { - // The tag is not a style tag. - if (theChildStyleStack) { - if (theStyleDoesntLeakOut) { - IF_DELETE(theChildStyleStack, &mNodeAllocator); - } else { - mBodyContext->PushStyles(theChildStyleStack); - } - } - } - IF_FREE(theNode, &mNodeAllocator); - } - } - 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 aTag -- - * @param aClosedByStartTag -- ONLY TRUE if the container is being closed by opening of another container. - * @return TRUE if ok, FALSE if error - */ -nsresult -CNavDTD::CloseContainersTo(eHTMLTags aTag, bool aClosedByStartTag) -{ - NS_PRECONDITION(mBodyContext->GetCount() > 0, kInvalidTagStackPos); - - int32_t pos = mBodyContext->LastOf(aTag); - - if (kNotFound != pos) { - // The tag is indeed open, so close it. - return CloseContainersTo(pos, aTag, aClosedByStartTag); - } - - eHTMLTags theTopTag = mBodyContext->Last(); - - bool theTagIsSynonymous = (nsHTMLElement::IsResidualStyleTag(aTag) && - nsHTMLElement::IsResidualStyleTag(theTopTag)) || - (gHTMLElements[aTag].IsMemberOf(kHeading) && - gHTMLElements[theTopTag].IsMemberOf(kHeading)); - - if (theTagIsSynonymous) { - // If you're here, it's because we're trying to close one tag, - // but a different (synonymous) one is actually open. Because this is NAV4x - // compatibililty mode, we must close the one that's really open. - aTag = theTopTag; - pos = mBodyContext->LastOf(aTag); - if (kNotFound != pos) { - // The tag is indeed open, so close it. - return CloseContainersTo(pos, aTag, aClosedByStartTag); - } - } - - nsresult result = NS_OK; - const TagList* theRootTags = gHTMLElements[aTag].GetRootTags(); - // XXX Can we just bail if !theRootTags? Does that ever happen? - eHTMLTags theParentTag = theRootTags ? theRootTags->mTags[0] : eHTMLTag_unknown; - pos = mBodyContext->LastOf(theParentTag); - if (kNotFound != pos) { - // The parent container is open, so close it instead - result = CloseContainersTo(pos + 1, aTag, aClosedByStartTag); - } - 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 error code; 0 means OK - */ -nsresult -CNavDTD::AddLeaf(const nsIParserNode *aNode) -{ - nsresult result = NS_OK; - - if (mSink) { - eHTMLTags theTag = (eHTMLTags)aNode->GetNodeType(); - OpenTransientStyles(theTag); - - result = mSink->AddLeaf(*aNode); - } - - return result; -} - -/** - * Call this method ONLY when you want to write a leaf - * into the head container. - * - * @update gess 03/14/99 - * @param aNode -- next node to be added to model - * @return error code; 0 means OK - */ -nsresult -CNavDTD::AddHeadContent(nsIParserNode *aNode) -{ - nsresult result = NS_OK; - - static eHTMLTags gNoXTags[] = { eHTMLTag_noembed, eHTMLTag_noframes }; - - eHTMLTags theTag = (eHTMLTags)aNode->GetNodeType(); - - // XXX - SCRIPT inside NOTAGS should not get executed unless the pref. - // says so. Since we don't have this support yet..lets ignore the - // SCRIPT inside NOTAGS. Ref Bug 25880. - if (eHTMLTag_meta == theTag || eHTMLTag_script == theTag) { - if (HasOpenContainer(gNoXTags, ArrayLength(gNoXTags))) { - return result; - } - } - - if (mSink) { - // Make sure the head is opened. - if (!(mFlags & NS_DTD_FLAG_HAS_OPEN_HEAD)) { - result = mSink->OpenHead(); - mBodyContext->PushTag(eHTMLTag_head); - mFlags |= NS_DTD_FLAG_HAS_OPEN_HEAD; - } - - // Note: userdefined tags in the head are treated as leaves. - if (!nsHTMLElement::IsContainer(theTag) || theTag == eHTMLTag_userdefined) { - result = mSink->AddLeaf(*aNode); - - if (mFlags & NS_DTD_FLAG_HAS_MAIN_CONTAINER) { - // Close the head now so that body content doesn't get sucked into it. - CloseContainer(eHTMLTag_head, false); - } - } else { - if ((mFlags & NS_DTD_FLAG_HAS_MAIN_CONTAINER) && - mHeadContainerPosition == -1) { - // Keep track of this so that we know when to close the head, when - // this tag is done with. - mHeadContainerPosition = mBodyContext->GetCount(); - } - - // Note: The head context is already opened. - result = mSink->OpenContainer(*aNode); - - mBodyContext->Push(static_cast<nsCParserNode*>(aNode), nullptr, - false); - } - } - - return result; -} - -void -CNavDTD::CreateContextStackFor(eHTMLTags aParent, eHTMLTags aChild) -{ - mScratch.Truncate(); - - bool result = ForwardPropagate(mScratch, aParent, aChild); - - if (!result) { - if (eHTMLTag_unknown == aParent) { - result = BackwardPropagate(mScratch, eHTMLTag_html, aChild); - } else if (aParent != aChild) { - // Don't even bother if we're already inside a similar element... - result = BackwardPropagate(mScratch, aParent, aChild); - } - } - - if (!result) { - return; - } - - int32_t theLen = mScratch.Length(); - eHTMLTags theTag = (eHTMLTags)mScratch[--theLen]; - - // Now, build up the stack according to the tags. - while (theLen) { - theTag = (eHTMLTags)mScratch[--theLen]; - - // Note: These tokens should all wind up on contextstack, so don't recycle - // them. - CToken *theToken = mTokenAllocator->CreateTokenOfType(eToken_start, theTag); - HandleToken(theToken); - } -}
--- a/parser/htmlparser/src/CNavDTD.h +++ b/parser/htmlparser/src/CNavDTD.h @@ -1,373 +1,38 @@ /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* vim: set sw=2 ts=2 et tw=78: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -/** - * MODULE NOTES: - * - * NavDTD is an implementation of the nsIDTD interface. - * In particular, this class captures the behaviors of the original - * Navigator parser productions. - * - * This DTD, like any other in NGLayout, provides a few basic services: - * - First, the DTD collaborates with the Parser class to convert plain - * text into a sequence of HTMLTokens. - * - Second, the DTD describes containment rules for known elements. - * - Third the DTD controls and coordinates the interaction between the - * parsing system and content sink. (The content sink is the interface - * that serves as a proxy for content model). - * - Fourth the DTD maintains an internal style-stack to handle residual (leaky) - * style tags. - * - * You're most likely working in this class file because - * you want to add or change a behavior inherent in this DTD. The remainder - * of this section will describe what you need to do to affect the kind of - * change you want in this DTD. - * - * RESIDUAL-STYLE HANDLNG: - * There are a number of ways to represent style in an HTML document. - * 1) explicit style tags (<B>, <I> etc) - * 2) implicit styles (like those implicit in <Hn>) - * 3) CSS based styles - * - * Residual style handling results from explicit style tags that are - * not closed. Consider this example: <p>text <b>bold </p> - * When the <p> tag closes, the <b> tag is NOT automatically closed. - * Unclosed style tags are handled by the process we call residual-style - * tag handling. - * - * There are two aspects to residual style tag handling. The first is the - * construction and managing of a stack of residual style tags. The - * second is the automatic emission of residual style tags onto leaf content - * in subsequent portions of the document.This step is necessary to propagate - * the expected style behavior to subsequent portions of the document. - * - * Construction and managing the residual style stack is an inline process that - * occurs during the model building phase of the parse process. During the model- - * building phase of the parse process, a content stack is maintained which tracks - * the open container hierarchy. If a style tag(s) fails to be closed when a normal - * container is closed, that style tag is placed onto the residual style stack. If - * that style tag is subsequently closed (in most contexts), it is popped off the - * residual style stack -- and are of no further concern. - * - * Residual style tag emission occurs when the style stack is not empty, and leaf - * content occurs. In our earlier example, the <b> tag "leaked" out of the <p> - * container. Just before the next leaf is emitted (in this or another container) the - * style tags that are on the stack are emitted in succession. These same residual - * style tags get closed automatically when the leaf's container closes, or if a - * child container is opened. - * - * - */ #ifndef NS_NAVHTMLDTD__ #define NS_NAVHTMLDTD__ #include "nsIDTD.h" #include "nsISupports.h" -#include "nsHTMLTags.h" -#include "nsDeque.h" -#include "nsParserCIID.h" -#include "nsDTDUtils.h" -#include "nsParser.h" -#include "nsCycleCollectionParticipant.h" +#include "nsCOMPtr.h" +// This class is no longer useful. class nsIHTMLContentSink; -class nsIParserNode; -class nsDTDContext; -class nsEntryStack; -class nsITokenizer; -class nsCParserNode; -class nsTokenAllocator; - -/*************************************************************** - Now the main event: CNavDTD. - - This not so simple class performs all the duties of token - construction and model building. It works in conjunction with - an nsParser. - ***************************************************************/ #ifdef _MSC_VER #pragma warning( disable : 4275 ) #endif class CNavDTD : public nsIDTD { #ifdef _MSC_VER #pragma warning( default : 4275 ) #endif public: - /** - * Common constructor for navdtd. You probably want to call - * NS_NewNavHTMLDTD(). - */ CNavDTD(); virtual ~CNavDTD(); - /** - * This method is offered publically for the sole use from - * nsParser::ParseFragment. In general, you should prefer to use methods - * that are directly on nsIDTD, since those will be guaranteed to do the - * right thing. - * - * @param aNode The parser node that contains the token information for - * this tag. - * @param aTag The actual tag that is being opened (should correspond to - * aNode. - * @param aStyleStack The style stack that aNode might be a member of - * (usually null). - */ - nsresult OpenContainer(const nsCParserNode *aNode, - eHTMLTags aTag, - nsEntryStack* aStyleStack = nullptr); - - NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_ISUPPORTS NS_DECL_NSIDTD - NS_DECL_CYCLE_COLLECTION_CLASS(CNavDTD) - -private: - /** - * This method is called to determine whether or not a tag - * of one type can contain a tag of another type. - * - * @param aParent Tag of parent container - * @param aChild Tag of child container - * @return true if parent can contain child - */ - bool CanPropagate(eHTMLTags aParent, - eHTMLTags aChild, - int32_t aParentContains); - - /** - * This method gets called to determine whether a given - * child tag can be omitted by the given parent. - * - * @param aParent Parent tag being asked about omitting given child - * @param aChild Child tag being tested for omittability by parent - * @param aParentContains Can be 0,1,-1 (false,true, unknown) - * XXX should be int32_t, not bool - * @return true if given tag can be omitted - */ - bool CanOmit(eHTMLTags aParent, - eHTMLTags aChild, - int32_t& aParentContains); - - /** - * Looking at aParent, try to see if we can propagate from aChild to - * aParent. If aParent is a TR tag, then see if we can start at TD instead - * of at aChild. - * - * @param aParent Tag type of parent - * @param aChild Tag type of child - * @return true if closure was achieved -- otherwise false - */ - bool ForwardPropagate(nsString& aSequence, - eHTMLTags aParent, - eHTMLTags aChild); - - /** - * Given aParent that does not contain aChild, starting with aChild's - * first root tag, try to find aParent. If we can reach aParent simply by - * going up each first root tag, then return true. Otherwise, we could not - * propagate from aChild up to aParent, so return false. - * - * @param aParent Tag type of parent - * @param aChild Tag type of child - * @return true if closure was achieved -- other false - */ - bool BackwardPropagate(nsString& aSequence, - eHTMLTags aParent, - eHTMLTags aChild) const; - - /** - * Attempt forward and/or backward propagation for the given child within - * the current context vector stack. And actually open the required tags. - * - * @param aParent The tag we're trying to open this element inside of. - * @param aChild Type of child to be propagated. - */ - void CreateContextStackFor(eHTMLTags aParent, eHTMLTags aChild); - - /** - * Ask if a given container is open anywhere on its stack - * - * @param id of container you want to test for - * @return TRUE if the given container type is open -- otherwise FALSE - */ - bool HasOpenContainer(eHTMLTags aContainer) const; - - /** - * This method allows the caller to determine if a any member - * in a set of tags is currently open. - * - * @param aTagSet A set of tags you care about. - * @return true if any of the members of aTagSet are currently open. - */ - bool HasOpenContainer(const eHTMLTags aTagSet[], int32_t aCount) const; - - /** - * Accessor that retrieves the tag type of the topmost item on the DTD's - * tag stack. - * - * @return The tag type (may be unknown) - */ - eHTMLTags GetTopNode() const; - - /** - * Finds the topmost occurrence of given tag within context vector stack. - * - * @param tag to be found - * @return index of topmost tag occurrence -- may be -1 (kNotFound). - */ - int32_t LastOf(eHTMLTags aTagSet[], int32_t aCount) const; - - nsresult HandleToken(CToken* aToken); - - /** - * This method gets called when a start token has been - * encountered in the parse process. If the current container - * can contain this tag, then add it. Otherwise, you have - * two choices: 1) create an implicit container for this tag - * to be stored in - * 2) close the top container, and add this to - * whatever container ends up on top. - * - * @param aToken -- next (start) token to be handled - * @return Whether or not we should block the parser. - */ - nsresult HandleStartToken(CToken* aToken); - - /** - * This method gets called when a start token has been - * encountered in the parse process. If the current container - * can contain this tag, then add it. Otherwise, you have - * two choices: 1) create an implicit container for this tag - * to be stored in - * 2) close the top container, and add this to - * whatever container ends up on top. - * - * @param aToken Next (start) token to be handled. - * @param aChildTag The tag corresponding to aToken. - * @param aNode CParserNode representing this start token - * @return A potential request to block the parser. - */ - nsresult HandleDefaultStartToken(CToken* aToken, eHTMLTags aChildTag, - nsCParserNode *aNode); - nsresult HandleEndToken(CToken* aToken); - nsresult HandleEntityToken(CToken* aToken); - nsresult HandleCommentToken(CToken* aToken); - nsresult HandleAttributeToken(CToken* aToken); - nsresult HandleProcessingInstructionToken(CToken* aToken); - nsresult HandleDocTypeDeclToken(CToken* aToken); - nsresult BuildNeglectedTarget(eHTMLTags aTarget, eHTMLTokenTypes aType); - - nsresult OpenHTML(const nsCParserNode *aNode); - nsresult OpenBody(const nsCParserNode *aNode); - - /** - * The special purpose methods automatically close - * one or more open containers. - * @return error code - 0 if all went well. - */ - nsresult CloseContainer(const eHTMLTags aTag, bool aMalformed); - nsresult CloseContainersTo(eHTMLTags aTag, bool aClosedByStartTag); - nsresult CloseContainersTo(int32_t anIndex, eHTMLTags aTag, - bool aClosedByStartTag); - nsresult CloseResidualStyleTags(const eHTMLTags aTag, - bool aClosedByStartTag); - - /** - * Causes leaf to be added to sink at current vector pos. - * @param aNode is leaf node to be added. - * @return error code - 0 if all went well. - */ - nsresult AddLeaf(const nsIParserNode *aNode); - nsresult AddHeadContent(nsIParserNode *aNode); - - /** - * This set of methods is used to create and manage the set of - * transient styles that occur as a result of poorly formed HTML - * or bugs in the original navigator. - * - * @param aTag -- represents the transient style tag to be handled. - * @return error code -- usually 0 - */ - nsresult OpenTransientStyles(eHTMLTags aChildTag, - bool aCloseInvalid = true); - void PopStyle(eHTMLTags aTag); - - nsresult PushIntoMisplacedStack(CToken* aToken) - { - NS_ENSURE_ARG_POINTER(aToken); - aToken->SetNewlineCount(0); // Note: We have already counted the newlines for these tokens - - mMisplacedContent.Push(aToken); - return NS_OK; - } - -protected: - - nsresult CollectAttributes(nsIParserNode* aNode,eHTMLTags aTag,int32_t aCount); - - /** - * This gets called before we've handled a given start tag. - * It's a generic hook to let us do pre processing. - * - * @param aToken contains the tag in question - * @param aTag is the tag itself. - * @param aNode is the node (tag) with associated attributes. - * @return NS_OK if we should continue, a failure code otherwise. - */ - nsresult WillHandleStartTag(CToken* aToken,eHTMLTags aChildTag,nsIParserNode& aNode); - nsresult DidHandleStartTag(nsIParserNode& aNode,eHTMLTags aChildTag); - - /** - * This method gets called when a start token has been encountered that - * the parent wants to omit. It stashes it in the current element if that - * element accepts such misplaced tokens. - * - * @param aToken Next (start) token to be handled - * @param aChildTag id of the child in question - * @param aParent id of the parent in question - * @param aNode CParserNode representing this start token - */ - void HandleOmittedTag(CToken* aToken, eHTMLTags aChildTag, - eHTMLTags aParent, nsIParserNode *aNode); - nsresult HandleSavedTokens(int32_t anIndex); - nsresult HandleKeyGen(nsIParserNode *aNode); - bool IsAlternateTag(eHTMLTags aTag); - bool IsBlockElement(int32_t aTagID, int32_t aParentID) const; - bool IsInlineElement(int32_t aTagID, int32_t aParentID) const; - - nsDeque mMisplacedContent; - - nsCOMPtr<nsIHTMLContentSink> mSink; - nsTokenAllocator* mTokenAllocator; - nsDTDContext* mBodyContext; - nsDTDContext* mTempContext; - bool mCountLines; - nsITokenizer* mTokenizer; // weak - - nsString mFilename; - nsString mScratch; //used for various purposes; non-persistent - nsCString mMimeType; - - nsNodeAllocator mNodeAllocator; - nsDTDMode mDTDMode; - eParserDocType mDocType; - eParserCommands mParserCommand; //tells us to viewcontent/viewsource/viewerrors... - - int32_t mLineNumber; - int32_t mOpenMapCount; - int32_t mHeadContainerPosition; - - uint16_t mFlags; }; -#endif +#endif
--- a/parser/htmlparser/src/CParserContext.cpp +++ b/parser/htmlparser/src/CParserContext.cpp @@ -7,16 +7,17 @@ #include "nsIAtom.h" #include "CParserContext.h" #include "nsToken.h" #include "prenv.h" #include "nsIHTMLContentSink.h" #include "nsHTMLTokenizer.h" #include "nsMimeTypes.h" +#include "nsHTMLTokenizer.h" CParserContext::CParserContext(CParserContext* aPrevContext, nsScanner* aScanner, void *aKey, eParserCommands aCommand, nsIRequestObserver* aListener, eAutoDetectResult aStatus, bool aCopyUnused) @@ -73,22 +74,16 @@ CParserContext::GetTokenizer(nsIDTD* aDT if (!mTokenizer) { if (type == NS_IPARSER_FLAG_HTML || mParserCommand == eViewSource) { nsCOMPtr<nsIHTMLContentSink> theSink = do_QueryInterface(aSink); mTokenizer = new nsHTMLTokenizer(mDTDMode, mDocType, mParserCommand, nsHTMLTokenizer::GetFlags(aSink)); if (!mTokenizer) { return NS_ERROR_OUT_OF_MEMORY; } - - // Make sure the new tokenizer has all of the necessary information. - // XXX this might not be necessary. - if (mPrevContext) { - mTokenizer->CopyState(mPrevContext->mTokenizer); - } } else if (type == NS_IPARSER_FLAG_XML) { mTokenizer = do_QueryInterface(aDTD, &result); } } aTokenizer = mTokenizer;
--- a/parser/htmlparser/src/moz.build +++ b/parser/htmlparser/src/moz.build @@ -4,27 +4,24 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. MODULE = 'htmlparser' CPP_SOURCES += [ 'CNavDTD.cpp', 'CParserContext.cpp', - 'nsDTDUtils.cpp', 'nsElementTable.cpp', 'nsExpatDriver.cpp', 'nsHTMLEntities.cpp', 'nsHTMLTags.cpp', 'nsHTMLTokenizer.cpp', - 'nsHTMLTokens.cpp', 'nsParser.cpp', 'nsParserModule.cpp', 'nsParserMsgUtils.cpp', 'nsParserNode.cpp', 'nsParserService.cpp', 'nsScanner.cpp', 'nsScannerString.cpp', - 'nsToken.cpp', ] LIBRARY_NAME = 'htmlpars'
deleted file mode 100644 --- a/parser/htmlparser/src/nsDTDUtils.cpp +++ /dev/null @@ -1,985 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 sw=2 et tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - - -#include "nsIAtom.h" -#include "nsDTDUtils.h" -#include "CNavDTD.h" -#include "nsIParserNode.h" -#include "nsParserNode.h" -#include "nsIChannel.h" -#include "nsIServiceManager.h" -#include "nsUnicharUtils.h" - -/************************************************************************************** - A few notes about how residual style handling is performed: - - 1. The style stack contains nsTagEntry elements. - 2. Every tag on the containment stack can have it's own residual style stack. - 3. When a style leaks, it's mParent member is set to the level on the stack where - it originated. A node with an mParent of 0 is not opened on tag stack, - but is open on stylestack. - 4. An easy way to tell that a container on the element stack is a residual style tag - is that it's use count is >1. - - **************************************************************************************/ - - -/** - * Default constructor - * @update harishd 04/04/99 - * @update gess 04/22/99 - */ -nsEntryStack::nsEntryStack() { - - MOZ_COUNT_CTOR(nsEntryStack); - - mCapacity=0; - mCount=0; - mEntries=0; -} - -/** - * Default destructor - * @update harishd 04/04/99 - * @update gess 04/22/99 - */ -nsEntryStack::~nsEntryStack() { - - MOZ_COUNT_DTOR(nsEntryStack); - - if(mEntries) { - //add code here to recycle the node if you have one... - delete [] mEntries; - mEntries=0; - } - - mCount=mCapacity=0; -} - -/** - * Release all objects in the entry stack - */ -void -nsEntryStack::ReleaseAll(nsNodeAllocator* aNodeAllocator) -{ - NS_ASSERTION(aNodeAllocator,"no allocator? - potential leak!"); - - if(aNodeAllocator) { - NS_ASSERTION(mCount >= 0,"count should not be negative"); - while(mCount > 0) { - nsCParserNode* node=this->Pop(); - IF_FREE(node,aNodeAllocator); - } - } -} - -/** - * Resets state of stack to be empty. - * @update harishd 04/04/99 - */ -void nsEntryStack::Empty(void) { - mCount=0; -} - - -/** - * - * @update gess 04/22/99 - */ -void nsEntryStack::EnsureCapacityFor(int32_t aNewMax,int32_t aShiftOffset) { - if(mCapacity<aNewMax){ - - const int kDelta=16; - - int32_t theSize = kDelta * ((aNewMax / kDelta) + 1); - nsTagEntry* temp=new nsTagEntry[theSize]; - mCapacity=theSize; - - if(temp){ - int32_t index=0; - for(index=0;index<mCount;++index) { - temp[aShiftOffset+index]=mEntries[index]; - } - if(mEntries) delete [] mEntries; - mEntries=temp; - } - else{ - //XXX HACK! This is very bad! We failed to get memory. - } - } //if -} - -/** - * - * @update gess 04/22/99 - */ -void nsEntryStack::Push(nsCParserNode* aNode, - nsEntryStack* aStyleStack, - bool aRefCntNode) -{ - if(aNode) { - EnsureCapacityFor(mCount+1); - mEntries[mCount].mTag = (eHTMLTags)aNode->GetNodeType(); - if (aRefCntNode) { - aNode->mUseCount++; - mEntries[mCount].mNode = const_cast<nsCParserNode*>(aNode); - IF_HOLD(mEntries[mCount].mNode); - } - mEntries[mCount].mParent=aStyleStack; - mEntries[mCount++].mStyles=0; - } -} - -void nsEntryStack::PushTag(eHTMLTags aTag) -{ - EnsureCapacityFor(mCount + 1); - mEntries[mCount].mTag = aTag; - mEntries[mCount].mParent = nullptr; - mEntries[mCount].mStyles = nullptr; - ++mCount; -} - - -/** - * This method inserts the given node onto the front of this stack - * - * @update gess 11/10/99 - */ -void nsEntryStack::PushFront(nsCParserNode* aNode, - nsEntryStack* aStyleStack, - bool aRefCntNode) -{ - if(aNode) { - if(mCount<mCapacity) { - int32_t index=0; - for(index=mCount;index>0;index--) { - mEntries[index]=mEntries[index-1]; - } - } - else { - EnsureCapacityFor(mCount+1,1); - } - mEntries[0].mTag = (eHTMLTags)aNode->GetNodeType(); - if (aRefCntNode) { - aNode->mUseCount++; - mEntries[0].mNode = const_cast<nsCParserNode*>(aNode); - IF_HOLD(mEntries[0].mNode); - } - mEntries[0].mParent=aStyleStack; - mEntries[0].mStyles=0; - ++mCount; - } -} - -/** - * - * @update gess 11/10/99 - */ -void nsEntryStack::Append(nsEntryStack *aStack) { - if(aStack) { - - int32_t theCount=aStack->mCount; - - EnsureCapacityFor(mCount+aStack->mCount,0); - - int32_t theIndex=0; - for(theIndex=0;theIndex<theCount;++theIndex){ - mEntries[mCount]=aStack->mEntries[theIndex]; - mEntries[mCount++].mParent=0; - } - } -} - -/** - * This method removes the node for the given tag - * from anywhere within this entry stack, and shifts - * other entries down. - * - * NOTE: It's odd to be removing an element from the middle - * of a stack, but it's necessary because of how MALFORMED - * html can be. - * - * anIndex: the index within the stack of the tag to be removed - * aTag: the id of the tag to be removed - * @update gess 02/25/00 - */ -nsCParserNode* nsEntryStack::Remove(int32_t anIndex, - eHTMLTags aTag) -{ - nsCParserNode* result = 0; - if (0 < mCount && anIndex < mCount){ - result = mEntries[anIndex].mNode; - if (result) - result->mUseCount--; - int32_t theIndex = 0; - mCount -= 1; - for( theIndex = anIndex; theIndex < mCount; ++theIndex){ - mEntries[theIndex] = mEntries[theIndex+1]; - } - mEntries[mCount].mNode = 0; - mEntries[mCount].mStyles = 0; - nsEntryStack* theStyleStack = mEntries[anIndex].mParent; - if (theStyleStack) { - //now we have to tell the residual style stack where this tag - //originated that it's no longer in use. - uint32_t scount = theStyleStack->mCount; -#ifdef DEBUG_mrbkap - NS_ASSERTION(scount != 0, "RemoveStyles has a bad style stack"); -#endif - nsTagEntry *theStyleEntry = theStyleStack->mEntries; - for (uint32_t sindex = scount-1;; --sindex) { - if (theStyleEntry->mTag == aTag) { - // This tells us that the style is not open at any level. - theStyleEntry->mParent = nullptr; - break; - } - if (sindex == 0) { -#ifdef DEBUG_mrbkap - NS_ERROR("Couldn't find the removed style on its parent stack"); -#endif - break; - } - ++theStyleEntry; - } - } - } - return result; -} - -/** - * Pops an entry from this style stack. If the entry has a parent stack, it - * updates the entry so that we know not to try to remove it from the parent - * stack since it's no longer open. - */ -nsCParserNode* nsEntryStack::Pop(void) -{ - nsCParserNode* result = 0; - if (0 < mCount) { - result = mEntries[--mCount].mNode; - if (result) - result->mUseCount--; - mEntries[mCount].mNode = 0; - mEntries[mCount].mStyles = 0; - nsEntryStack* theStyleStack = mEntries[mCount].mParent; - if (theStyleStack) { - //now we have to tell the residual style stack where this tag - //originated that it's no longer in use. - uint32_t scount = theStyleStack->mCount; - - // XXX If this NS_ENSURE_TRUE fails, it means that the style stack was - // empty before we were removed. -#ifdef DEBUG_mrbkap - NS_ASSERTION(scount != 0, "preventing a potential crash."); -#endif - NS_ENSURE_TRUE(scount != 0, result); - - nsTagEntry *theStyleEntry = theStyleStack->mEntries; - for (uint32_t sindex = scount - 1;; --sindex) { - if (theStyleEntry->mTag == mEntries[mCount].mTag) { - // This tells us that the style is not open at any level - theStyleEntry->mParent = nullptr; - break; - } - if (sindex == 0) { -#ifdef DEBUG_mrbkap - NS_ERROR("Couldn't find the removed style on its parent stack"); -#endif - break; - } - ++theStyleEntry; - } - } - } - return result; -} - -/** - * - * @update harishd 04/04/99 - * @update gess 04/21/99 - */ -eHTMLTags nsEntryStack::First() const -{ - eHTMLTags result=eHTMLTag_unknown; - if(0<mCount){ - result=mEntries[0].mTag; - } - return result; -} - -/** - * - * @update harishd 04/04/99 - * @update gess 04/21/99 - */ -nsCParserNode* nsEntryStack::NodeAt(int32_t anIndex) const -{ - nsCParserNode* result=0; - if((0<mCount) && (anIndex<mCount)) { - result=mEntries[anIndex].mNode; - } - return result; -} - -/** - * - * @update harishd 04/04/99 - * @update gess 04/21/99 - */ -eHTMLTags nsEntryStack::TagAt(int32_t anIndex) const -{ - eHTMLTags result=eHTMLTag_unknown; - if((0<mCount) && (anIndex<mCount)) { - result=mEntries[anIndex].mTag; - } - return result; -} - -/** - * - * @update gess 04/21/99 - */ -nsTagEntry* nsEntryStack::EntryAt(int32_t anIndex) const -{ - nsTagEntry *result=0; - if((0<mCount) && (anIndex<mCount)) { - result=&mEntries[anIndex]; - } - return result; -} - - -/** - * - * @update harishd 04/04/99 - * @update gess 04/21/99 - */ -eHTMLTags nsEntryStack::operator[](int32_t anIndex) const -{ - eHTMLTags result=eHTMLTag_unknown; - if((0<mCount) && (anIndex<mCount)) { - result=mEntries[anIndex].mTag; - } - return result; -} - - -/** - * - * @update harishd 04/04/99 - * @update gess 04/21/99 - */ -eHTMLTags nsEntryStack::Last(void) const -{ - eHTMLTags result=eHTMLTag_unknown; - if(0<mCount) { - result=mEntries[mCount-1].mTag; - } - return result; -} - -nsTagEntry* -nsEntryStack::PopEntry() -{ - nsTagEntry* entry = EntryAt(mCount-1); - this->Pop(); - return entry; -} - -void nsEntryStack::PushEntry(nsTagEntry* aEntry, - bool aRefCntNode) -{ - if (aEntry) { - EnsureCapacityFor(mCount+1); - mEntries[mCount].mNode = aEntry->mNode; - mEntries[mCount].mTag = aEntry->mTag; - mEntries[mCount].mParent = aEntry->mParent; - mEntries[mCount].mStyles = aEntry->mStyles; - if (aRefCntNode && mEntries[mCount].mNode) { - mEntries[mCount].mNode->mUseCount++; - IF_HOLD(mEntries[mCount].mNode); - } - mCount++; - } -} - -/*************************************************************** - Now define the dtdcontext class - ***************************************************************/ - - -/** - * - * @update gess 04.21.2000 - */ -nsDTDContext::nsDTDContext() : mStack() -{ - MOZ_COUNT_CTOR(nsDTDContext); - mResidualStyleCount=0; - mContextTopIndex=-1; - mTokenAllocator=0; - mNodeAllocator=0; - -#ifdef DEBUG - memset(mXTags,0,sizeof(mXTags)); -#endif -} - -/** - * - * @update gess9/10/98 - */ -nsDTDContext::~nsDTDContext() -{ - MOZ_COUNT_DTOR(nsDTDContext); -} - - -/** - * - * @update gess7/9/98 - */ -bool nsDTDContext::HasOpenContainer(eHTMLTags aTag) const { - int32_t theIndex=mStack.LastOf(aTag); - return bool(-1<theIndex); -} - -/** - * - * @update gess7/9/98 - */ -void nsDTDContext::Push(nsCParserNode* aNode, - nsEntryStack* aStyleStack, - bool aRefCntNode) { - if(aNode) { -#ifdef DEBUG - eHTMLTags theTag = (eHTMLTags)aNode->GetNodeType(); - int size = mStack.mCount; - if (size < eMaxTags) - mXTags[size] = theTag; -#endif - mStack.Push(aNode, aStyleStack, aRefCntNode); - } -} - -void nsDTDContext::PushTag(eHTMLTags aTag) -{ -#ifdef DEBUG - if (mStack.mCount < eMaxTags) { - mXTags[mStack.mCount] = aTag; - } -#endif - - mStack.PushTag(aTag); -} - -nsTagEntry* -nsDTDContext::PopEntry() -{ - int32_t theSize = mStack.mCount; - if(0<theSize) { -#ifdef DEBUG - if (theSize <= eMaxTags) - mXTags[theSize-1]=eHTMLTag_unknown; -#endif - return mStack.PopEntry(); - } - return 0; -} - -void nsDTDContext::PushEntry(nsTagEntry* aEntry, - bool aRefCntNode) -{ -#ifdef DEBUG - int size=mStack.mCount; - if(size< eMaxTags && aEntry) - mXTags[size]=aEntry->mTag; -#endif - mStack.PushEntry(aEntry, aRefCntNode); -} - -/* This method will move the top entries, in the entry-stack, into dest context. - * @param aDest - Destination context for the entries. - * @param aCount - Number of entries, on top of the entry-stack, to be moved. - */ -void -nsDTDContext::MoveEntries(nsDTDContext& aDest, - int32_t aCount) -{ - NS_ASSERTION(aCount > 0 && mStack.mCount >= aCount, "cannot move entries"); - if (aCount > 0 && mStack.mCount >= aCount) { - while (aCount) { - aDest.PushEntry(&mStack.mEntries[--mStack.mCount], false); -#ifdef DEBUG - if (mStack.mCount < eMaxTags) { - mXTags[mStack.mCount] = eHTMLTag_unknown; - } -#endif - --aCount; - } - } -} - -/** - * @update gess 11/11/99, - * harishd 04/04/99 - */ -nsCParserNode* nsDTDContext::Pop(nsEntryStack *&aChildStyleStack) { - - int32_t theSize=mStack.mCount; - nsCParserNode* result=0; - - if(0<theSize) { - -#ifdef DEBUG - if ((theSize>0) && (theSize <= eMaxTags)) - mXTags[theSize-1]=eHTMLTag_unknown; -#endif - - - nsTagEntry* theEntry=mStack.EntryAt(mStack.mCount-1); - aChildStyleStack=theEntry->mStyles; - - result=mStack.Pop(); - theEntry->mParent=0; - } - - return result; -} - -/** - * - * @update harishd 04/07/00 - */ - -nsCParserNode* nsDTDContext::Pop() { - nsEntryStack *theTempStyleStack=0; // This has no use here... - return Pop(theTempStyleStack); -} - -/** - * - * @update gess7/9/98 - */ -eHTMLTags nsDTDContext::First(void) const { - return mStack.First(); -} - -/** - * - * @update gess7/9/98 - */ -eHTMLTags nsDTDContext::TagAt(int32_t anIndex) const { - return mStack.TagAt(anIndex); -} - -/** - * - * @update gess7/9/98 - */ -nsTagEntry* nsDTDContext::LastEntry(void) const { - return mStack.EntryAt(mStack.mCount-1); -} - -/** - * - * @update gess7/9/98 - */ -eHTMLTags nsDTDContext::Last() const { - return mStack.Last(); -} - - -/** - * - * @update gess7/9/98 - */ -nsEntryStack* nsDTDContext::GetStylesAt(int32_t anIndex) const { - nsEntryStack* result=0; - - if(anIndex<mStack.mCount){ - nsTagEntry* theEntry=mStack.EntryAt(anIndex); - if(theEntry) { - result=theEntry->mStyles; - } - } - return result; -} - - -/** - * - * @update gess 04/28/99 - */ -void nsDTDContext::PushStyle(nsCParserNode* aNode){ - - nsTagEntry* theEntry=mStack.EntryAt(mStack.mCount-1); - if(theEntry ) { - nsEntryStack* theStack=theEntry->mStyles; - if(!theStack) { - theStack=theEntry->mStyles=new nsEntryStack(); - } - if(theStack) { - theStack->Push(aNode); - ++mResidualStyleCount; - } - } //if -} - - -/** - * Call this when you have an EntryStack full of styles - * that you want to push at this level. - * - * @update gess 04/28/99 - */ -void nsDTDContext::PushStyles(nsEntryStack *aStyles){ - - if(aStyles) { - nsTagEntry* theEntry=mStack.EntryAt(mStack.mCount-1); - if(theEntry ) { - nsEntryStack* theStyles=theEntry->mStyles; - if(!theStyles) { - theEntry->mStyles=aStyles; - - uint32_t scount=aStyles->mCount; - uint32_t sindex=0; - - theEntry=aStyles->mEntries; - for(sindex=0;sindex<scount;++sindex){ - theEntry->mParent=0; //this tells us that the style is not open at any level - ++theEntry; - ++mResidualStyleCount; - } //for - - } - else { - theStyles->Append(aStyles); - // Delete aStyles since it has been copied to theStyles... - delete aStyles; - aStyles=0; - } - } //if(theEntry ) - else if(mStack.mCount==0) { - // If you're here it means that we have hit the rock bottom - // ,of the stack, and there's no need to handle anymore styles. - // Fix for bug 29048 - IF_DELETE(aStyles,mNodeAllocator); - } - }//if(aStyles) -} - - -/** - * - * @update gess 04/28/99 - */ -nsCParserNode* nsDTDContext::PopStyle(void){ - nsCParserNode *result=0; - - nsTagEntry *theEntry=mStack.EntryAt(mStack.mCount-1); - if(theEntry && (theEntry->mNode)) { - nsEntryStack* theStyleStack=theEntry->mParent; - if(theStyleStack){ - result=theStyleStack->Pop(); - mResidualStyleCount--; - } - } //if - return result; -} - -/** - * - * @update gess 04/28/99 - */ -nsCParserNode* nsDTDContext::PopStyle(eHTMLTags aTag){ - - int32_t theLevel=0; - nsCParserNode* result=0; - - for(theLevel=mStack.mCount-1;theLevel>0;theLevel--) { - nsEntryStack *theStack=mStack.mEntries[theLevel].mStyles; - if(theStack) { - if(aTag==theStack->Last()) { - result=theStack->Pop(); - mResidualStyleCount--; - break; // Fix bug 50710 - Stop after finding a style. - } else { - // NS_ERROR("bad residual style entry"); - } - } - } - - return result; -} - -/** - * - * This is similar to popstyle, except that it removes the - * style tag given from anywhere in the style stack, and - * not just at the top. - * - * @update gess 01/26/00 - */ -void nsDTDContext::RemoveStyle(eHTMLTags aTag){ - - int32_t theLevel=mStack.mCount; - - while (theLevel) { - nsEntryStack *theStack=GetStylesAt(--theLevel); - if (theStack) { - int32_t index=theStack->mCount; - while (index){ - nsTagEntry *theEntry=theStack->EntryAt(--index); - if (aTag==(eHTMLTags)theEntry->mNode->GetNodeType()) { - mResidualStyleCount--; - nsCParserNode* result=theStack->Remove(index,aTag); - IF_FREE(result, mNodeAllocator); - return; - } - } - } - } -} - -/** - * This gets called when the parser module is getting unloaded - * - * @return nada - */ -void nsDTDContext::ReleaseGlobalObjects(void){ -} - - -/************************************************************** - Now define the nsTokenAllocator class... - **************************************************************/ - -/** - * - * @update gess7/25/98 - * @param - */ -nsTokenAllocator::nsTokenAllocator() { - - MOZ_COUNT_CTOR(nsTokenAllocator); - -#ifdef DEBUG - int i=0; - for(i=0;i<eToken_last-1;++i) { - mTotals[i]=0; - } -#endif - -} - -/** - * Destructor for the token factory - * @update gess7/25/98 - */ -nsTokenAllocator::~nsTokenAllocator() { - - MOZ_COUNT_DTOR(nsTokenAllocator); - -} - -class CTokenFinder: public nsDequeFunctor{ -public: - CTokenFinder(CToken* aToken) {mToken=aToken;} - virtual void* operator()(void* anObject) { - if(anObject==mToken) { - return anObject; - } - return 0; - } - CToken* mToken; -}; - -/** - * Let's get this code ready to be reused by all the contexts. - * - * @update rickg 12June2000 - * @param aType -- tells you the type of token to create - * @param aTag -- tells you the type of tag to init with this token - * @param aString -- gives a default string value for the token - * - * @return ptr to new token (or 0). - */ -CToken* nsTokenAllocator::CreateTokenOfType(eHTMLTokenTypes aType,eHTMLTags aTag, const nsAString& aString) { - - CToken* result=0; - -#ifdef DEBUG - mTotals[aType-1]++; -#endif - switch(aType){ - case eToken_start: result=new(mArenaPool) CStartToken(aString, aTag); break; - case eToken_end: result=new(mArenaPool) CEndToken(aString, aTag); break; - case eToken_comment: result=new(mArenaPool) CCommentToken(aString); break; - case eToken_entity: result=new(mArenaPool) CEntityToken(aString); break; - case eToken_whitespace: result=new(mArenaPool) CWhitespaceToken(aString); break; - case eToken_newline: result=new(mArenaPool) CNewlineToken(); break; - case eToken_text: result=new(mArenaPool) CTextToken(aString); break; - case eToken_attribute: result=new(mArenaPool) CAttributeToken(aString); break; - case eToken_instruction: result=new(mArenaPool) CInstructionToken(aString); break; - case eToken_cdatasection: result=new(mArenaPool) CCDATASectionToken(aString); break; - case eToken_doctypeDecl: result=new(mArenaPool) CDoctypeDeclToken(aString); break; - case eToken_markupDecl: result=new(mArenaPool) CMarkupDeclToken(aString); break; - default: - NS_ASSERTION(false, "nsDTDUtils::CreateTokenOfType: illegal token type"); - break; - } - - return result; -} - -/** - * Let's get this code ready to be reused by all the contexts. - * - * @update rickg 12June2000 - * @param aType -- tells you the type of token to create - * @param aTag -- tells you the type of tag to init with this token - * - * @return ptr to new token (or 0). - */ -CToken* nsTokenAllocator::CreateTokenOfType(eHTMLTokenTypes aType,eHTMLTags aTag) { - - CToken* result=0; - -#ifdef DEBUG - mTotals[aType-1]++; -#endif - switch(aType){ - case eToken_start: result=new(mArenaPool) CStartToken(aTag); break; - case eToken_end: result=new(mArenaPool) CEndToken(aTag); break; - case eToken_comment: result=new(mArenaPool) CCommentToken(); break; - case eToken_attribute: result=new(mArenaPool) CAttributeToken(); break; - case eToken_entity: result=new(mArenaPool) CEntityToken(); break; - case eToken_whitespace: result=new(mArenaPool) CWhitespaceToken(); break; - case eToken_newline: result=new(mArenaPool) CNewlineToken(); break; - case eToken_text: result=new(mArenaPool) CTextToken(); break; - case eToken_instruction: result=new(mArenaPool) CInstructionToken(); break; - case eToken_cdatasection: result=new(mArenaPool) CCDATASectionToken(aTag); break; - case eToken_doctypeDecl: result=new(mArenaPool) CDoctypeDeclToken(aTag); break; - case eToken_markupDecl: result=new(mArenaPool) CMarkupDeclToken(); break; - default: - NS_ASSERTION(false, "nsDTDUtils::CreateTokenOfType: illegal token type"); - break; - } - - return result; -} - -#ifdef DEBUG_TRACK_NODES - -static nsCParserNode* gAllNodes[100]; -static int gAllNodeCount=0; - -int FindNode(nsCParserNode *aNode) { - int theIndex=0; - for(theIndex=0;theIndex<gAllNodeCount;++theIndex) { - if(gAllNodes[theIndex]==aNode) { - return theIndex; - } - } - return -1; -} - -void AddNode(nsCParserNode *aNode) { - if(-1==FindNode(aNode)) { - gAllNodes[gAllNodeCount++]=aNode; - } - else { - //you tried to recycle a node twice! - } -} - -void RemoveNode(nsCParserNode *aNode) { - int theIndex=FindNode(aNode); - if(-1<theIndex) { - gAllNodes[theIndex]=gAllNodes[--gAllNodeCount]; - } -} - -#endif - - -#ifdef HEAP_ALLOCATED_NODES -nsNodeAllocator::nsNodeAllocator():mSharedNodes(0){ -#ifdef DEBUG_TRACK_NODES - mCount=0; -#endif -#else -nsNodeAllocator::nsNodeAllocator() { -#endif - MOZ_COUNT_CTOR(nsNodeAllocator); -} - -nsNodeAllocator::~nsNodeAllocator() { - MOZ_COUNT_DTOR(nsNodeAllocator); - -#ifdef HEAP_ALLOCATED_NODES - nsCParserNode* theNode = 0; - - while((theNode=(nsCParserNode*)mSharedNodes.Pop())){ -#ifdef DEBUG_TRACK_NODES - RemoveNode(theNode); -#endif - ::operator delete(theNode); - theNode=nullptr; - } -#ifdef DEBUG_TRACK_NODES - if(mCount) { - printf("**************************\n"); - printf("%i out of %i nodes leaked!\n",gAllNodeCount,mCount); - printf("**************************\n"); - } -#endif -#endif -} - -nsCParserNode* nsNodeAllocator::CreateNode(CToken* aToken, - nsTokenAllocator* aTokenAllocator) -{ - nsCParserNode* result = 0; -#ifdef HEAP_ALLOCATED_NODES -#if 0 - if(gAllNodeCount!=mSharedNodes.GetSize()) { - int x=10; //this is very BAD! - } -#endif - result = static_cast<nsCParserNode*>(mSharedNodes.Pop()); - if (result) { - result->Init(aToken, aTokenAllocator,this); - } - else{ - result = nsCParserNode::Create(aToken, aTokenAllocator,this); -#ifdef DEBUG_TRACK_NODES - ++mCount; - AddNode(static_cast<nsCParserNode*>(result)); -#endif - IF_HOLD(result); - } -#else - eHTMLTokenTypes type = aToken ? eHTMLTokenTypes(aToken->GetTokenType()) : eToken_unknown; - switch (type) { - case eToken_start: - result = nsCParserStartNode::Create(aToken, aTokenAllocator,this); - break; - default : - result = nsCParserNode::Create(aToken, aTokenAllocator,this); - break; - } - IF_HOLD(result); -#endif - return result; -} - -#ifdef DEBUG -void DebugDumpContainmentRules(nsIDTD& theDTD,const char* aFilename,const char* aTitle) { -} -#endif
deleted file mode 100644 --- a/parser/htmlparser/src/nsDTDUtils.h +++ /dev/null @@ -1,453 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 sw=2 et tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - - -/** - * MODULE NOTES: - * @update gess 4/1/98 - * - */ - - - -#ifndef DTDUTILS_ -#define DTDUTILS_ - -#include "nsHTMLTags.h" -#include "nsHTMLTokens.h" -#include "nsIParser.h" -#include "nsCRT.h" -#include "nsDeque.h" -#include "nsIDTD.h" -#include "nsITokenizer.h" -#include "nsString.h" -#include "nsIParserNode.h" -#include "nsCOMArray.h" -#include "nsIParserService.h" -#include "nsReadableUtils.h" -#include "nsIHTMLContentSink.h" -#include "nsIFrame.h" - -#define IF_HOLD(_ptr) \ - PR_BEGIN_MACRO \ - if(_ptr) { \ - _ptr->AddRef(); \ - } \ - PR_END_MACRO - -// recycles _ptr -#define IF_FREE(_ptr, _allocator) \ - PR_BEGIN_MACRO \ - if(_ptr && _allocator) { \ - _ptr->Release((_allocator)->GetArenaPool()); \ - _ptr=0; \ - } \ - PR_END_MACRO - -// release objects and destroy _ptr -#define IF_DELETE(_ptr, _allocator) \ - PR_BEGIN_MACRO \ - if(_ptr) { \ - _ptr->ReleaseAll(_allocator); \ - delete(_ptr); \ - _ptr=0; \ - } \ - PR_END_MACRO - -class nsIParserNode; -class nsCParserNode; -class nsNodeAllocator; - - -#ifdef DEBUG -void DebugDumpContainmentRules(nsIDTD& theDTD,const char* aFilename,const char* aTitle); -void DebugDumpContainmentRules2(nsIDTD& theDTD,const char* aFilename,const char* aTitle); -#endif - -/*************************************************************** - First, define the tagstack class - ***************************************************************/ - -class nsEntryStack; //forware declare to make compilers happy. - -struct nsTagEntry { - nsTagEntry () - : mTag(eHTMLTag_unknown), mNode(0), mParent(0), mStyles(0){} - eHTMLTags mTag; //for speedier access to tag id - nsCParserNode* mNode; - nsEntryStack* mParent; - nsEntryStack* mStyles; -}; - -class nsEntryStack { - -public: - nsEntryStack(); - ~nsEntryStack(); - - nsTagEntry* PopEntry(); - void PushEntry(nsTagEntry* aEntry, bool aRefCntNode = true); - void EnsureCapacityFor(int32_t aNewMax, int32_t aShiftOffset=0); - void Push(nsCParserNode* aNode,nsEntryStack* aStyleStack=0, bool aRefCntNode = true); - void PushTag(eHTMLTags aTag); - void PushFront(nsCParserNode* aNode,nsEntryStack* aStyleStack=0, bool aRefCntNode = true); - void Append(nsEntryStack *aStack); - nsCParserNode* Pop(void); - nsCParserNode* Remove(int32_t anIndex,eHTMLTags aTag); - nsCParserNode* NodeAt(int32_t anIndex) const; - eHTMLTags First() const; - eHTMLTags TagAt(int32_t anIndex) const; - nsTagEntry* EntryAt(int32_t anIndex) const; - eHTMLTags operator[](int32_t anIndex) const; - eHTMLTags Last() const; - void Empty(void); - - /* - * Release all objects in the entry stack - */ - void ReleaseAll(nsNodeAllocator* aNodeAllocator); - - /** - * Find the first instance of given tag on the stack. - * @update gess 12/14/99 - * @param aTag - * @return index of tag, or kNotFound if not found - */ - inline int32_t FirstOf(eHTMLTags aTag) const { - int32_t index=-1; - - if(0<mCount) { - while(++index<mCount) { - if(aTag==mEntries[index].mTag) { - return index; - } - } //while - } - return kNotFound; - } - - - /** - * Find the last instance of given tag on the stack. - * @update gess 12/14/99 - * @param aTag - * @return index of tag, or kNotFound if not found - */ - inline int32_t LastOf(eHTMLTags aTag) const { - int32_t index=mCount; - while(--index>=0) { - if(aTag==mEntries[index].mTag) { - return index; - } - } - return kNotFound; - } - - nsTagEntry* mEntries; - int32_t mCount; - int32_t mCapacity; -}; - - -/********************************************************** - The table state class is used to store info about each - table that is opened on the stack. As tables open and - close on the context, we update these objects to track - what has/hasn't been seen on a per table basis. - **********************************************************/ -class CTableState { -public: - CTableState(CTableState *aPreviousState=0) { - mHasCaption=false; - mHasCols=false; - mHasTHead=false; - mHasTFoot=false; - mHasTBody=false; - mPrevious=aPreviousState; - } - - bool CanOpenCaption() { - bool result=!(mHasCaption || mHasCols || mHasTHead || mHasTFoot || mHasTBody); - return result; - } - - bool CanOpenCols() { - bool result=!(mHasCols || mHasTHead || mHasTFoot || mHasTBody); - return result; - } - - bool CanOpenTBody() { - bool result=!(mHasTBody); - return result; - } - - bool CanOpenTHead() { - bool result=!(mHasTHead || mHasTFoot || mHasTBody); - return result; - } - - bool CanOpenTFoot() { - bool result=!(mHasTFoot || mHasTBody); - return result; - } - - bool mHasCaption; - bool mHasCols; - bool mHasTHead; - bool mHasTFoot; - bool mHasTBody; - CTableState *mPrevious; -}; - -/************************************************************************ - nsTokenAllocator class implementation. - This class is used to recycle tokens. - By using this simple class, we cut WAY down on the number of tokens - that get created during the run of the system. - - Note: The allocator is created per document. It's been shared - ( but not ref. counted ) by objects, tokenizer,dtd,and dtd context, - that cease to exist when the document is destroyed. - ************************************************************************/ -class nsTokenAllocator -{ -public: - - nsTokenAllocator(); - ~nsTokenAllocator(); - CToken* CreateTokenOfType(eHTMLTokenTypes aType,eHTMLTags aTag, const nsAString& aString); - CToken* CreateTokenOfType(eHTMLTokenTypes aType,eHTMLTags aTag); - - nsDummyAllocator& GetArenaPool() { return mArenaPool; } - -protected: - nsDummyAllocator mArenaPool; -#ifdef DEBUG - int mTotals[eToken_last-1]; -#endif -}; - -/************************************************************************ - CNodeRecycler class implementation. - This class is used to recycle nodes. - By using this simple class, we cut down on the number of nodes - that get created during the run of the system. - ************************************************************************/ - -#ifndef HEAP_ALLOCATED_NODES -class nsCParserNode; -#endif - -class nsNodeAllocator -{ -public: - - nsNodeAllocator(); - ~nsNodeAllocator(); - nsCParserNode* CreateNode(CToken* aToken=nullptr, nsTokenAllocator* aTokenAllocator=0); - - nsDummyAllocator& GetArenaPool() { return mNodePool; } - -#ifdef HEAP_ALLOCATED_NODES - void Recycle(nsCParserNode* aNode) { mSharedNodes.Push(static_cast<void*>(aNode)); } -protected: - nsDeque mSharedNodes; -#ifdef DEBUG_TRACK_NODES - int32_t mCount; -#endif -#endif - -protected: - nsDummyAllocator mNodePool; -}; - -/************************************************************************ - The dtdcontext class defines an ordered list of tags (a context). - ************************************************************************/ - -class nsDTDContext -{ -public: - nsDTDContext(); - ~nsDTDContext(); - - nsTagEntry* PopEntry(); - void PushEntry(nsTagEntry* aEntry, bool aRefCntNode = true); - void MoveEntries(nsDTDContext& aDest, int32_t aCount); - void Push(nsCParserNode* aNode,nsEntryStack* aStyleStack=0, bool aRefCntNode = true); - void PushTag(eHTMLTags aTag); - nsCParserNode* Pop(nsEntryStack*& aChildStack); - nsCParserNode* Pop(); - nsCParserNode* PeekNode() { return mStack.NodeAt(mStack.mCount-1); } - eHTMLTags First(void) const; - eHTMLTags Last(void) const; - nsTagEntry* LastEntry(void) const; - eHTMLTags TagAt(int32_t anIndex) const; - eHTMLTags operator[](int32_t anIndex) const {return TagAt(anIndex);} - bool HasOpenContainer(eHTMLTags aTag) const; - int32_t FirstOf(eHTMLTags aTag) const {return mStack.FirstOf(aTag);} - int32_t LastOf(eHTMLTags aTag) const {return mStack.LastOf(aTag);} - - void Empty(void); - int32_t GetCount(void) const {return mStack.mCount;} - int32_t GetResidualStyleCount(void) {return mResidualStyleCount;} - nsEntryStack* GetStylesAt(int32_t anIndex) const; - void PushStyle(nsCParserNode* aNode); - void PushStyles(nsEntryStack *aStyles); - nsCParserNode* PopStyle(void); - nsCParserNode* PopStyle(eHTMLTags aTag); - void RemoveStyle(eHTMLTags aTag); - - static void ReleaseGlobalObjects(void); - - void SetTokenAllocator(nsTokenAllocator* aTokenAllocator) { mTokenAllocator=aTokenAllocator; } - void SetNodeAllocator(nsNodeAllocator* aNodeAllocator) { mNodeAllocator=aNodeAllocator; } - - nsEntryStack mStack; //this will hold a list of tagentries... - int32_t mResidualStyleCount; - int32_t mContextTopIndex; - - nsTokenAllocator *mTokenAllocator; - nsNodeAllocator *mNodeAllocator; - -#ifdef DEBUG - enum { eMaxTags = MAX_REFLOW_DEPTH }; - eHTMLTags mXTags[eMaxTags]; -#endif -}; - -/************************************************************** - Now define the token deallocator class... - **************************************************************/ -class CTokenDeallocator: public nsDequeFunctor{ -protected: - nsDummyAllocator& mArenaPool; - -public: - CTokenDeallocator(nsDummyAllocator& aArenaPool) - : mArenaPool(aArenaPool) {} - - virtual void* operator()(void* anObject) { - CToken* aToken = (CToken*)anObject; - aToken->Release(mArenaPool); - return 0; - } -}; - - -/************************************************************************ - ITagHandler class offers an API for taking care of specific tokens. - ************************************************************************/ -class nsITagHandler { -public: - - virtual void SetString(const nsString &aTheString)=0; - virtual nsString* GetString()=0; - virtual bool HandleToken(CToken* aToken,nsIDTD* aDTD)=0; - virtual bool HandleCapturedTokens(CToken* aToken,nsIDTD* aDTD)=0; -}; - -/************************************************************************ - Here are a few useful utility methods... - ************************************************************************/ - -/** - * This method quickly scans the given set of tags, - * looking for the given tag. - * @update gess8/27/98 - * @param aTag -- tag to be search for in set - * @param aTagSet -- set of tags to be searched - * @return - */ -inline int32_t IndexOfTagInSet(int32_t aTag,const eHTMLTags* aTagSet,int32_t aCount) { - - const eHTMLTags* theEnd=aTagSet+aCount; - const eHTMLTags* theTag=aTagSet; - - while(theTag<theEnd) { - if(aTag==*theTag) { - return theTag-aTagSet; - } - ++theTag; - } - - return kNotFound; -} - -/** - * This method quickly scans the given set of tags, - * looking for the given tag. - * @update gess8/27/98 - * @param aTag -- tag to be search for in set - * @param aTagSet -- set of tags to be searched - * @return - */ -inline bool FindTagInSet(int32_t aTag,const eHTMLTags *aTagSet,int32_t aCount) { - return bool(-1<IndexOfTagInSet(aTag,aTagSet,aCount)); -} - -/*********************************************************************************************/ - -struct TagList { - size_t mCount; - const eHTMLTags *mTags; -}; - -/** - * Find the last member of given taglist on the given context - * @update gess 12/14/99 - * @param aContext - * @param aTagList - * @return index of tag, or kNotFound if not found - */ -inline int32_t LastOf(nsDTDContext& aContext, const TagList& aTagList){ - int max = aContext.GetCount(); - int index; - for(index=max-1;index>=0;index--){ - bool result=FindTagInSet(aContext[index],aTagList.mTags,aTagList.mCount); - if(result) { - return index; - } - } - return kNotFound; -} - -/** - * Find the first member of given taglist on the given context - * @update gess 12/14/99 - * @param aContext - * @param aStartOffset - * @param aTagList - * @return index of tag, or kNotFound if not found - */ -inline int32_t FirstOf(nsDTDContext& aContext,int32_t aStartOffset,TagList& aTagList){ - int max = aContext.GetCount(); - int index; - for(index=aStartOffset;index<max;++index){ - bool result=FindTagInSet(aContext[index],aTagList.mTags,aTagList.mCount); - if(result) { - return index; - } - } - return kNotFound; -} - - -/** - * Call this to find out whether the DTD thinks the tag requires an END tag </xxx> - * @update gess 01/04/99 - * @param id of tag - * @return TRUE of the element's end tag is optional - */ -inline bool HasOptionalEndTag(eHTMLTags aTag) { - static eHTMLTags gHasOptionalEndTags[]={eHTMLTag_body,eHTMLTag_colgroup,eHTMLTag_dd,eHTMLTag_dt, - eHTMLTag_head,eHTMLTag_li,eHTMLTag_option, - eHTMLTag_p,eHTMLTag_tbody,eHTMLTag_td,eHTMLTag_tfoot, - eHTMLTag_th,eHTMLTag_thead,eHTMLTag_tr, - eHTMLTag_userdefined,eHTMLTag_unknown}; - return FindTagInSet(aTag,gHasOptionalEndTags,sizeof(gHasOptionalEndTags)/sizeof(eHTMLTag_body)); -} -#endif
--- a/parser/htmlparser/src/nsElementTable.cpp +++ b/parser/htmlparser/src/nsElementTable.cpp @@ -7,2225 +7,577 @@ #include "nsIAtom.h" #include "nsElementTable.h" /***************************************************************************** Now it's time to list all the html elements all with their capabilities... ******************************************************************************/ -#define DECL_TAG_LIST(name_, list_) \ - static const eHTMLTags name_##list[] = list_; \ - static const TagList name_ = { NS_ARRAY_LENGTH(name_##list), name_##list }; - -#define COMMA , - -//First, define the set of taglists for tags with special parents... -DECL_TAG_LIST(gAParents,{eHTMLTag_map}) -DECL_TAG_LIST(gInAddress,{eHTMLTag_address}) -DECL_TAG_LIST(gInHead,{eHTMLTag_head}) -DECL_TAG_LIST(gInTable,{eHTMLTag_table}) -DECL_TAG_LIST(gInHTML,{eHTMLTag_html}) -DECL_TAG_LIST(gInBody,{eHTMLTag_body}) -DECL_TAG_LIST(gInForm,{eHTMLTag_form}) -DECL_TAG_LIST(gInFieldset,{eHTMLTag_fieldset}) -DECL_TAG_LIST(gInTR,{eHTMLTag_tr}) -DECL_TAG_LIST(gInDL,{eHTMLTag_dl COMMA eHTMLTag_body}) -DECL_TAG_LIST(gInFrameset,{eHTMLTag_frameset}) -DECL_TAG_LIST(gInNoframes,{eHTMLTag_noframes}) -//Removed ADDRESS to solve 24885 -// gInP: nsHTMLElement::CanContain() also allows table in Quirks mode for bug 43678, removed FORM bug 94269 -DECL_TAG_LIST(gInP,{eHTMLTag_span}) -DECL_TAG_LIST(gOptgroupParents,{eHTMLTag_select COMMA eHTMLTag_optgroup}) -DECL_TAG_LIST(gBodyParents,{eHTMLTag_html COMMA eHTMLTag_noframes}) -DECL_TAG_LIST(gColParents,{eHTMLTag_table COMMA eHTMLTag_colgroup}) -DECL_TAG_LIST(gFramesetParents,{eHTMLTag_html COMMA eHTMLTag_frameset}) -DECL_TAG_LIST(gLegendParents,{eHTMLTag_fieldset}) -DECL_TAG_LIST(gAreaParent,{eHTMLTag_map}) -DECL_TAG_LIST(gParamParents,{eHTMLTag_applet COMMA eHTMLTag_object}) -DECL_TAG_LIST(gTRParents,{eHTMLTag_tbody COMMA eHTMLTag_tfoot COMMA eHTMLTag_thead COMMA eHTMLTag_table}) -DECL_TAG_LIST(gTREndParents,{eHTMLTag_tbody COMMA eHTMLTag_tfoot COMMA eHTMLTag_thead COMMA eHTMLTag_table COMMA eHTMLTag_applet}) -DECL_TAG_LIST(gSourceParents,{eHTMLTag_video COMMA eHTMLTag_audio}) -DECL_TAG_LIST(gTrackParents,{eHTMLTag_video COMMA eHTMLTag_audio}) - -//********************************************************************************************* -// Next, define the set of taglists for tags with special kids... -//********************************************************************************************* - -DECL_TAG_LIST(gContainsText,{eHTMLTag_text COMMA eHTMLTag_newline COMMA eHTMLTag_whitespace COMMA eHTMLTag_entity}) -DECL_TAG_LIST(gUnknownKids,{eHTMLTag_html COMMA eHTMLTag_frameset}) - -// The presence of <input>, <select>, and <textarea> in gContainsOpts is due to -// the exclgroup that <select> sets... If I don't include those here, they -// just get dropped automatically, since they are not allowed to open inside -// <select>. Note that we are NOT allowing them to actually open without -// closing the select -- see gInputAutoClose. Further note that I'm not -// including <button> in the list because in IE it doesn't autoclose <select>! -DECL_TAG_LIST(gContainsOpts,{eHTMLTag_option COMMA eHTMLTag_optgroup COMMA eHTMLTag_script COMMA eHTMLTag_input COMMA eHTMLTag_select COMMA eHTMLTag_textarea }) -// Similar deal for <option> except it allows all of gContainsText _and_ the things that should autoclose selects. -DECL_TAG_LIST(gContainedInOpt,{eHTMLTag_text COMMA eHTMLTag_newline COMMA eHTMLTag_whitespace COMMA eHTMLTag_entity COMMA eHTMLTag_input COMMA eHTMLTag_select COMMA eHTMLTag_textarea}) -DECL_TAG_LIST(gContainsParam,{eHTMLTag_param}) -DECL_TAG_LIST(gColgroupKids,{eHTMLTag_col}) -DECL_TAG_LIST(gAddressKids,{eHTMLTag_p}) -DECL_TAG_LIST(gBodyKids,{eHTMLTag_dd COMMA eHTMLTag_del COMMA eHTMLTag_dt COMMA eHTMLTag_ins COMMA eHTMLTag_noscript COMMA eHTMLTag_script COMMA eHTMLTag_li COMMA eHTMLTag_param}) // Added PARAM for bug 54448 -DECL_TAG_LIST(gButtonKids,{eHTMLTag_caption COMMA eHTMLTag_legend}) - -DECL_TAG_LIST(gDLRootTags,{eHTMLTag_body COMMA eHTMLTag_td COMMA eHTMLTag_table COMMA eHTMLTag_applet COMMA eHTMLTag_dd}) -DECL_TAG_LIST(gDLKids,{eHTMLTag_dd COMMA eHTMLTag_dt}) -DECL_TAG_LIST(gDTKids,{eHTMLTag_dt}) -DECL_TAG_LIST(gFieldsetKids,{eHTMLTag_legend COMMA eHTMLTag_text}) -DECL_TAG_LIST(gFontKids,{eHTMLTag_legend COMMA eHTMLTag_table COMMA eHTMLTag_text COMMA eHTMLTag_li}) // Added table to fix bug 93365, li to fix bug 96031 -DECL_TAG_LIST(gFormKids,{eHTMLTag_keygen}) -DECL_TAG_LIST(gFramesetKids,{eHTMLTag_frame COMMA eHTMLTag_frameset COMMA eHTMLTag_noframes}) - -DECL_TAG_LIST(gHtmlKids,{eHTMLTag_body COMMA eHTMLTag_frameset COMMA eHTMLTag_head COMMA eHTMLTag_noscript COMMA eHTMLTag_noframes COMMA eHTMLTag_script COMMA eHTMLTag_newline COMMA eHTMLTag_whitespace}) - -DECL_TAG_LIST(gLabelKids,{eHTMLTag_span}) -DECL_TAG_LIST(gLIKids,{eHTMLTag_ol COMMA eHTMLTag_ul}) -DECL_TAG_LIST(gMapKids,{eHTMLTag_area}) -DECL_TAG_LIST(gPreKids,{eHTMLTag_hr COMMA eHTMLTag_center}) //note that CENTER is here for backward compatibility; it's not 4.0 spec. - -DECL_TAG_LIST(gTableKids,{eHTMLTag_caption COMMA eHTMLTag_col COMMA eHTMLTag_colgroup COMMA eHTMLTag_form COMMA eHTMLTag_thead COMMA eHTMLTag_tbody COMMA eHTMLTag_tfoot COMMA eHTMLTag_script})// Removed INPUT - Ref. Bug 20087, 25382 - -DECL_TAG_LIST(gTableElemKids,{eHTMLTag_form COMMA eHTMLTag_noscript COMMA eHTMLTag_script COMMA eHTMLTag_td COMMA eHTMLTag_th COMMA eHTMLTag_tr}) -DECL_TAG_LIST(gTRKids,{eHTMLTag_td COMMA eHTMLTag_th COMMA eHTMLTag_form COMMA eHTMLTag_script})// Removed INPUT - Ref. Bug 20087, 25382 | Removed MAP to fix 58942 -DECL_TAG_LIST(gTBodyKids,{eHTMLTag_tr COMMA eHTMLTag_form}) // Removed INPUT - Ref. Bug 20087, 25382 -DECL_TAG_LIST(gULKids,{eHTMLTag_li COMMA eHTMLTag_p}) -DECL_TAG_LIST(gVideoKids,{eHTMLTag_source COMMA eHTMLTag_track}) -DECL_TAG_LIST(gAudioKids,{eHTMLTag_source COMMA eHTMLTag_track}) - -//********************************************************************************************* -// The following tag lists are used to define common set of root notes for the HTML elements... -//********************************************************************************************* - -DECL_TAG_LIST(gRootTags,{eHTMLTag_body COMMA eHTMLTag_td COMMA eHTMLTag_table COMMA eHTMLTag_applet COMMA eHTMLTag_select}) // Added SELECT to fix bug 98645 -DECL_TAG_LIST(gTableRootTags,{eHTMLTag_applet COMMA eHTMLTag_body COMMA eHTMLTag_dl COMMA eHTMLTag_ol COMMA eHTMLTag_td COMMA eHTMLTag_th}) -DECL_TAG_LIST(gHTMLRootTags,{eHTMLTag_unknown}) - -DECL_TAG_LIST(gLIRootTags,{eHTMLTag_ul COMMA eHTMLTag_ol COMMA eHTMLTag_dir COMMA eHTMLTag_menu COMMA eHTMLTag_p COMMA eHTMLTag_body COMMA eHTMLTag_td COMMA eHTMLTag_th}) - -DECL_TAG_LIST(gOLRootTags,{eHTMLTag_body COMMA eHTMLTag_li COMMA eHTMLTag_td COMMA eHTMLTag_th COMMA eHTMLTag_select}) -DECL_TAG_LIST(gTDRootTags,{eHTMLTag_tr COMMA eHTMLTag_tbody COMMA eHTMLTag_thead COMMA eHTMLTag_tfoot COMMA eHTMLTag_table COMMA eHTMLTag_applet}) -DECL_TAG_LIST(gNoframeRoot,{eHTMLTag_body COMMA eHTMLTag_frameset}) - -//********************************************************************************************* -// The following tag lists are used to define the autoclose properties of the html elements... -//********************************************************************************************* - -DECL_TAG_LIST(gBodyAutoClose,{eHTMLTag_head}) -DECL_TAG_LIST(gTBodyAutoClose,{eHTMLTag_thead COMMA eHTMLTag_tfoot COMMA eHTMLTag_tbody COMMA eHTMLTag_td COMMA eHTMLTag_th}) // TD|TH inclusion - Bug# 24112 -DECL_TAG_LIST(gCaptionAutoClose,{eHTMLTag_tbody}) -DECL_TAG_LIST(gLIAutoClose,{eHTMLTag_p COMMA eHTMLTag_li}) -DECL_TAG_LIST(gPAutoClose,{eHTMLTag_p COMMA eHTMLTag_li}) -DECL_TAG_LIST(gHRAutoClose,{eHTMLTag_p}) -DECL_TAG_LIST(gOLAutoClose,{eHTMLTag_p COMMA eHTMLTag_ol}) -DECL_TAG_LIST(gDivAutoClose,{eHTMLTag_p}) -// Form controls that autoclose <select> use this -DECL_TAG_LIST(gInputAutoClose,{eHTMLTag_select COMMA eHTMLTag_optgroup COMMA eHTMLTag_option}) - -DECL_TAG_LIST(gHeadingTags,{eHTMLTag_h1 COMMA eHTMLTag_h2 COMMA eHTMLTag_h3 COMMA eHTMLTag_h4 COMMA eHTMLTag_h5 COMMA eHTMLTag_h6}) - -DECL_TAG_LIST(gTableCloseTags,{eHTMLTag_td COMMA eHTMLTag_tr COMMA eHTMLTag_th COMMA eHTMLTag_tbody COMMA eHTMLTag_thead COMMA eHTMLTag_tfoot}) -DECL_TAG_LIST(gTRCloseTags,{eHTMLTag_tr COMMA eHTMLTag_td COMMA eHTMLTag_th}) -DECL_TAG_LIST(gTDCloseTags,{eHTMLTag_td COMMA eHTMLTag_th}) -DECL_TAG_LIST(gDTCloseTags,{eHTMLTag_p COMMA eHTMLTag_dd COMMA eHTMLTag_dt}) -DECL_TAG_LIST(gULCloseTags,{eHTMLTag_li}) -DECL_TAG_LIST(gULAutoClose,{eHTMLTag_p COMMA eHTMLTag_ul}) //fix bug 50261.. - -DECL_TAG_LIST(gExcludableParents,{eHTMLTag_pre}) // Ref Bug 22913 -DECL_TAG_LIST(gCaptionExcludableParents,{eHTMLTag_td}) //Ref Bug 26488 - -//********************************************************************************************* -//Lastly, bind tags with their rules, their special parents and special kids. -//********************************************************************************************* - - -const int kNoPropRange=0; -const int kDefaultPropRange=1; -const int kBodyPropRange=2; - -//********************************************************************************************* -// -// Now let's declare the element table... -// -//********************************************************************************************* - +// The Element Table (sung to the tune of Modern Major General) const nsHTMLElement gHTMLElements[] = { { - /*tag*/ eHTMLTag_unknown, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kNone, kNone, kNone, - /*special props, prop-range*/ kNonContainer, 10, - /*special parents,kids*/ 0,&gUnknownKids, + /*tag*/ eHTMLTag_unknown, + /*parent,leaf*/ kNone, true }, { - /*tag*/ eHTMLTag_a, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kSpecial, kInlineEntity, kNone, - /*special props, prop-range*/ kVerifyHierarchy, kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_a, + /*parent,leaf*/ kSpecial, false }, { - /*tag*/ eHTMLTag_abbr, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kPhrase, (kSelf|kInlineEntity), kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_abbr, + /*parent,leaf*/ kPhrase, false }, { - /*tag*/ eHTMLTag_acronym, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kPhrase, (kSelf|kInlineEntity), kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_acronym, + /*parent,leaf*/ kPhrase, false }, { - /*tag*/ eHTMLTag_address, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kBlock, kInlineEntity, kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,&gAddressKids, + /*tag*/ eHTMLTag_address, + /*parent,leaf*/ kBlock, false }, { - /*tag*/ eHTMLTag_applet, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kSpecial, (kSelf|kInlineEntity|kFlowEntity), kNone, - /*special props, prop-range*/ kRequiresBody,kDefaultPropRange, - /*special parents,kids*/ 0,&gContainsParam, + /*tag*/ eHTMLTag_applet, + /*parent,leaf*/ kSpecial, false }, { - /*tag*/ eHTMLTag_area, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gAreaParent,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kNone, kInlineEntity, kSelf, - /*special props, prop-range*/ kNonContainer,kDefaultPropRange, - /*special parents,kids*/ &gAreaParent,0, + /*tag*/ eHTMLTag_area, + /*parent,leaf*/ kNone, true }, { - /*tag*/ eHTMLTag_article, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kBlock, (kSelf|kFlowEntity), kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_article, + /*parent,leaf*/ kBlock, false }, { - /*tag*/ eHTMLTag_aside, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kBlock, (kSelf|kFlowEntity), kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_aside, + /*parent,leaf*/ kBlock, false }, { - /*tag*/ eHTMLTag_audio, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0, 0, 0,0, - /*parent,incl,exclgroups*/ kSpecial, (kFlowEntity|kSelf), kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,&gAudioKids, + /*tag*/ eHTMLTag_audio, + /*parent,leaf*/ kSpecial, false }, { - /*tag*/ eHTMLTag_b, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kFontStyle, (kInlineEntity|kSelf), kNone, - /*special props, prop-range*/ 0, kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_b, + /*parent,leaf*/ kFontStyle, false }, { - /*tag*/ eHTMLTag_base, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gInHead,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kHeadContent, kNone, kNone, - /*special props, prop-range*/ kNonContainer, kNoPropRange, - /*special parents,kids*/ &gInHead,0, + /*tag*/ eHTMLTag_base, + /*parent,leaf*/ kHeadContent, true }, { - /*tag*/ eHTMLTag_basefont, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kSpecial, kInlineEntity, kNone, - /*special props, prop-range*/ kNonContainer, kNoPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_basefont, + /*parent,leaf*/ kSpecial, true }, { - /*tag*/ eHTMLTag_bdo, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kSpecial, (kSelf|kInlineEntity), kNone, - /*special props, prop-range*/ 0, kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_bdo, + /*parent,leaf*/ kSpecial, false }, { - /*tag*/ eHTMLTag_bgsound, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ (kFlowEntity|kHeadMisc), kNone, kNone, - /*special props, prop-range*/ kNonContainer,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_bgsound, + /*parent,leaf*/ (kFlowEntity|kHeadMisc), true }, { - /*tag*/ eHTMLTag_big, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kFontStyle, (kInlineEntity|kSelf), kNone, - /*special props, prop-range*/ 0, kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_big, + /*parent,leaf*/ kFontStyle, false }, { - /*tag*/ eHTMLTag_blockquote, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, //remove excludeable parents to fix bug 53473 - /*parent,incl,exclgroups*/ kBlock, (kSelf|kFlowEntity), kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_blockquote, + /*parent,leaf*/ kBlock, false }, { - /*tag*/ eHTMLTag_body, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_frameset, - /*rootnodes,endrootnodes*/ &gInHTML,&gInHTML, - /*autoclose starttags and endtags*/ &gBodyAutoClose,0,0,0, - /*parent,incl,exclgroups*/ kHTMLContent,(kFlowEntity|kSelf), kNone, - /*special props, prop-range*/ kOmitEndTag, kBodyPropRange, - /*special parents,kids*/ 0,&gBodyKids, + /*tag*/ eHTMLTag_body, + /*parent,leaf*/ kHTMLContent, false }, { - /*tag*/ eHTMLTag_br, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kSpecial, kNone, kNone, - /*special props, prop-range*/ kRequiresBody|kNonContainer, kNoPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_br, + /*parent,leaf*/ kSpecial, true }, { - /*tag*/ eHTMLTag_button, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kFormControl, kFlowEntity, kFormControl, - /*special props, prop-range*/ kRequiresBody,kDefaultPropRange, - /*special parents,kids*/ 0,&gButtonKids, + /*tag*/ eHTMLTag_button, + /*parent,leaf*/ kFormControl, false }, { - /*tag*/ eHTMLTag_canvas, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kSpecial, (kFlowEntity|kSelf), kNone, - /*special props, prop-range*/ 0, kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_canvas, + /*parent,leaf*/ kSpecial, false }, { - /*tag*/ eHTMLTag_caption, - /*req-parent excl-parent*/ eHTMLTag_table,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gInTable,&gInTable, - /*autoclose starttags and endtags*/ &gCaptionAutoClose,0,0,0, - /*parent,incl,exclgroups*/ kNone, kFlowEntity, kSelf, - /*special props, prop-range*/ (kNoPropagate|kNoStyleLeaksOut),kDefaultPropRange, - /*special parents,kids*/ &gInTable,0, + /*tag*/ eHTMLTag_caption, + /*parent,leaf*/ kNone, false }, { - /*tag*/ eHTMLTag_center, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kBlock, (kSelf|kFlowEntity), kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_center, + /*parent,leaf*/ kBlock, false }, { - /*tag*/ eHTMLTag_cite, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kPhrase, (kSelf|kInlineEntity), kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_cite, + /*parent,leaf*/ kPhrase, false }, { - /*tag*/ eHTMLTag_code, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kPhrase, (kSelf|kInlineEntity), kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_code, + /*parent,leaf*/ kPhrase, false }, { - /*tag*/ eHTMLTag_col, - /*req-parent excl-parent*/ eHTMLTag_table,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gColParents,&gColParents, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kNone, kNone, kNone, - /*special props, prop-range*/ kNoPropagate|kNonContainer,kDefaultPropRange, - /*special parents,kids*/ &gColParents,0, + /*tag*/ eHTMLTag_col, + /*parent,leaf*/ kNone, true }, { - /*tag*/ eHTMLTag_colgroup, - /*req-parent excl-parent*/ eHTMLTag_table,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gInTable,&gInTable, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kNone, kNone, kNone, - /*special props, prop-range*/ kNoPropagate,kDefaultPropRange, - /*special parents,kids*/ &gInTable,&gColgroupKids, + /*tag*/ eHTMLTag_colgroup, + /*parent,leaf*/ kNone, false }, { - /*tag*/ eHTMLTag_data, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kPhrase, (kSelf|kInlineEntity), kNone, - /*special props, prop-range*/ 0, kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_data, + /*parent,leaf*/ kPhrase, false }, { - /*tag*/ eHTMLTag_datalist, - /*requiredAncestor*/ eHTMLTag_unknown, eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kSpecial, (kInlineEntity|kSelf|kFlowEntity), kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_datalist, + /*parent,leaf*/ kSpecial, false }, { - /*tag*/ eHTMLTag_dd, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ &gDTCloseTags,0,&gDLKids,0, - /*parent,incl,exclgroups*/ kInlineEntity, kFlowEntity, kNone, - /*special props, prop-range*/ kNoPropagate|kMustCloseSelf|kVerifyHierarchy|kRequiresBody,kDefaultPropRange, - /*special parents,kids*/ &gInDL,0, + /*tag*/ eHTMLTag_dd, + /*parent,leaf*/ kInlineEntity, false }, { - /*tag*/ eHTMLTag_del, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kFlowEntity, (kSelf|kFlowEntity), kNone, - /*special props, prop-range*/ 0, kDefaultPropRange, - /*special parents,kids*/ &gInBody,0, + /*tag*/ eHTMLTag_del, + /*parent,leaf*/ kFlowEntity, false }, { - /*tag*/ eHTMLTag_dfn, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kPhrase, (kSelf|kInlineEntity), kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_dfn, + /*parent,leaf*/ kPhrase, false }, { - /*tag*/ eHTMLTag_dir, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gOLRootTags,&gOLRootTags, - /*autoclose starttags and endtags*/ &gOLAutoClose, &gULCloseTags, 0,0, - /*parent,incl,exclgroups*/ kList, (kFlowEntity|kSelf), kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,&gULKids, + /*tag*/ eHTMLTag_dir, + /*parent,leaf*/ kList, false }, { - /*tag*/ eHTMLTag_div, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ &gDivAutoClose,0,0,0, - /*parent,incl,exclgroups*/ kBlock, (kSelf|kFlowEntity), kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_div, + /*parent,leaf*/ kBlock, false }, { - /*tag*/ eHTMLTag_dl, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gDLRootTags,&gRootTags, //fix bug 57634 - /*autoclose starttags and endtags*/ 0,0,0,&gDTKids, // DT should not contain DL - bug 100466 - /*parent,incl,exclgroups*/ kBlock, kSelf|kFlowEntity, kNone, - /*special props, prop-range*/ 0, kNoPropRange, - /*special parents,kids*/ 0,&gDLKids, + /*tag*/ eHTMLTag_dl, + /*parent,leaf*/ kBlock, false }, { - /*tag*/ eHTMLTag_dt, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ &gDTCloseTags,0,&gDLKids,0, - /*parent,incl,exclgroups*/ kInlineEntity, (kFlowEntity-kHeading), kNone, // dt's parent group is inline - bug 65467 - /*special props, prop-range*/ (kNoPropagate|kMustCloseSelf|kVerifyHierarchy|kRequiresBody),kDefaultPropRange, - /*special parents,kids*/ &gInDL,0, + /*tag*/ eHTMLTag_dt, + /*parent,leaf*/ kInlineEntity, false }, { - /*tag*/ eHTMLTag_em, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kPhrase, (kSelf|kInlineEntity), kNone, - /*special props, prop-range*/ 0, kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_em, + /*parent,leaf*/ kPhrase, false }, { - /*tag*/ eHTMLTag_embed, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kSpecial, kNone, kNone, - /*special props, prop-range*/ kNonContainer|kRequiresBody,kDefaultPropRange, - /*special parents,kids*/ 0,&gContainsParam, + /*tag*/ eHTMLTag_embed, + /*parent,leaf*/ kSpecial, true }, { - /*tag*/ eHTMLTag_fieldset, - /*requiredAncestor*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kBlock, (kSelf|kFlowEntity), kNone, - /*special props, prop-range*/ kNoPropagate,kDefaultPropRange, - /*special parents,kids*/ 0,&gFieldsetKids, + /*tag*/ eHTMLTag_fieldset, + /*parent,leaf*/ kBlock, false }, { - /*tag*/ eHTMLTag_figcaption, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kPhrase, (kSelf|kInlineEntity), kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_figcaption, + /*parent,leaf*/ kPhrase, false }, { - /*tag*/ eHTMLTag_figure, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kBlock, (kSelf|kFlowEntity), kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_figure, + /*parent,leaf*/ kBlock, false }, { - /*tag*/ eHTMLTag_font, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kFontStyle, (kSelf|kInlineEntity), kNone, - /*special props, prop-range*/ 0, kDefaultPropRange, - /*special parents,kids*/ 0,&gFontKids, + /*tag*/ eHTMLTag_font, + /*parent,leaf*/ kFontStyle, false }, { - /*tag*/ eHTMLTag_footer, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kBlock, (kSelf|kFlowEntity), kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_footer, + /*parent,leaf*/ kBlock, false }, { - /*tag*/ eHTMLTag_form, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kBlock, kFlowEntity, kNone, - /*special props, prop-range*/ kNoStyleLeaksIn, kNoPropRange, - /*special parents,kids*/ 0,&gFormKids, + /*tag*/ eHTMLTag_form, + /*parent,leaf*/ kBlock, false }, { - /*tag*/ eHTMLTag_frame, - /*req-parent excl-parent*/ eHTMLTag_frameset,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gInFrameset,&gInFrameset, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kNone, kNone, kNone, - /*special props, prop-range*/ kNoPropagate|kNoStyleLeaksIn|kNonContainer, kNoPropRange, - /*special parents,kids*/ &gInFrameset,0, + /*tag*/ eHTMLTag_frame, + /*parent,leaf*/ kNone, true + }, + { + /*tag*/ eHTMLTag_frameset, + /*parent,leaf*/ kHTMLContent, false }, { - /*tag*/ eHTMLTag_frameset, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_body, - /*rootnodes,endrootnodes*/ &gFramesetParents,&gInHTML, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kHTMLContent, kSelf, kAllTags, - /*special props, prop-range*/ kNoPropagate|kNoStyleLeaksIn, kNoPropRange, - /*special parents,kids*/ &gInHTML,&gFramesetKids, + /*tag*/ eHTMLTag_h1, + /*parent,leaf*/ kHeading, false }, - { - /*tag*/ eHTMLTag_h1, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ &gHeadingTags, &gHeadingTags, &gHeadingTags,0, - /*parent,incl,exclgroups*/ kHeading, kFlowEntity, kNone, - /*special props, prop-range*/ kVerifyHierarchy,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_h2, + /*parent,leaf*/ kHeading, false }, { - /*tag*/ eHTMLTag_h2, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ &gHeadingTags, &gHeadingTags, &gHeadingTags,0, - /*parent,incl,exclgroups*/ kHeading, kFlowEntity, kNone, - /*special props, prop-range*/ kVerifyHierarchy,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_h3, + /*parent,leaf*/ kHeading, false }, { - /*tag*/ eHTMLTag_h3, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ &gHeadingTags, &gHeadingTags, &gHeadingTags,0, - /*parent,incl,exclgroups*/ kHeading, kFlowEntity, kNone, - /*special props, prop-range*/ kVerifyHierarchy,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_h4, + /*parent,leaf*/ kHeading, false }, { - /*tag*/ eHTMLTag_h4, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ &gHeadingTags, &gHeadingTags, &gHeadingTags,0, - /*parent,incl,exclgroups*/ kHeading, kFlowEntity, kNone, - /*special props, prop-range*/ kVerifyHierarchy,kDefaultPropRange, - /*special parents,kids*/ 0,0, - }, - { - /*tag*/ eHTMLTag_h5, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ &gHeadingTags, &gHeadingTags, &gHeadingTags,0, - /*parent,incl,exclgroups*/ kHeading, kFlowEntity, kNone, - /*special props, prop-range*/ kVerifyHierarchy,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_h5, + /*parent,leaf*/ kHeading, false }, { - /*tag*/ eHTMLTag_h6, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ &gHeadingTags, &gHeadingTags, &gHeadingTags,0, - /*parent,incl,exclgroups*/ kHeading, kFlowEntity, kNone, - /*special props, prop-range*/ kVerifyHierarchy,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_h6, + /*parent,leaf*/ kHeading, false }, { - /*tag*/ eHTMLTag_head, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gInHTML,&gInHTML, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kHTMLContent, (kHeadContent|kHeadMisc), kNone, - /*special props, prop-range*/ kNoStyleLeaksIn, kDefaultPropRange, - /*special parents,kids*/ &gInHTML,0, + /*tag*/ eHTMLTag_head, + /*parent,leaf*/ kHTMLContent, false }, { - /*tag*/ eHTMLTag_header, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kBlock, (kSelf|kFlowEntity), kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_header, + /*parent,leaf*/ kBlock, false + }, + { + /*tag*/ eHTMLTag_hgroup, + /*parent,leaf*/ kBlock, false }, { - /*tag*/ eHTMLTag_hgroup, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kBlock, (kSelf|kFlowEntity), kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_hr, + /*parent,leaf*/ kBlock, true }, { - /*tag*/ eHTMLTag_hr, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ &gHRAutoClose,0,0,0, - /*parent,incl,exclgroups*/ kBlock, kNone, kNone, - /*special props, prop-range*/ kNonContainer|kRequiresBody,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_html, + /*parent,leaf*/ kNone, false }, { - /*tag*/ eHTMLTag_html, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_html, - /*rootnodes,endrootnodes*/ &gHTMLRootTags,&gHTMLRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kNone, kHTMLContent, kNone, - /*special props, prop-range*/ kSaveMisplaced|kOmitEndTag|kNoStyleLeaksIn, kDefaultPropRange, - /*special parents,kids*/ 0,&gHtmlKids, + /*tag*/ eHTMLTag_i, + /*parent,leaf*/ kFontStyle, false }, { - /*tag*/ eHTMLTag_i, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kFontStyle, (kSelf|kInlineEntity), kNone, - /*special props, prop-range*/ 0, kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_iframe, + /*parent,leaf*/ kSpecial, false }, { - /*tag*/ eHTMLTag_iframe, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kSpecial, (kSelf|kFlowEntity), kNone, - /*special props, prop-range*/ kNoStyleLeaksIn, kNoPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_image, + /*parent,leaf*/ kSpecial, true }, { - /*tag*/ eHTMLTag_image, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kSpecial, kNone, kNone, - /*special props, prop-range*/ kNonContainer,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_img, + /*parent,leaf*/ kSpecial, true }, { - /*tag*/ eHTMLTag_img, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kSpecial, kNone, kNone, - /*special props, prop-range*/ kNonContainer|kRequiresBody,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_input, + /*parent,leaf*/ kFormControl, true }, { - /*tag*/ eHTMLTag_input, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ &gInputAutoClose,0,0,0, - /*parent,incl,exclgroups*/ kFormControl, kNone, kNone, - /*special props, prop-range*/ kNonContainer|kRequiresBody,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_ins, + /*parent,leaf*/ kFlowEntity, false }, { - /*tag*/ eHTMLTag_ins, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kFlowEntity, (kSelf|kFlowEntity), kNone, - /*special props, prop-range*/ 0, kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_kbd, + /*parent,leaf*/ kPhrase, false }, { - /*tag*/ eHTMLTag_kbd, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kPhrase, (kSelf|kInlineEntity), kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_keygen, + /*parent,leaf*/ kFlowEntity, true }, { - /*tag*/ eHTMLTag_keygen, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kFlowEntity, kNone, kNone, - /*special props, prop-range*/ kNonContainer,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_label, + /*parent,leaf*/ kFormControl, false }, { - /*tag*/ eHTMLTag_label, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kFormControl, kInlineEntity, kSelf, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,&gLabelKids, + /*tag*/ eHTMLTag_legend, + /*parent,leaf*/ kNone, false }, { - /*tag*/ eHTMLTag_legend, - /*requiredAncestor*/ eHTMLTag_fieldset,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gInFieldset,&gInFieldset, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kNone, kInlineEntity, kNone, - /*special props, prop-range*/ kRequiresBody,kDefaultPropRange, - /*special parents,kids*/ &gInFieldset,0, + /*tag*/ eHTMLTag_li, + /*parent,leaf*/ kBlockEntity, false }, { - /*tag*/ eHTMLTag_li, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gLIRootTags,&gLIRootTags, - /*autoclose starttags and endtags*/ &gLIAutoClose,0,0,0, - /*parent,incl,exclgroups*/ kBlockEntity, kFlowEntity, kSelf, // changed this back to kBlockEntity so we enable RS handling for phrasals. ref bug 181697 - /*special props, prop-range*/ kNoPropagate|kVerifyHierarchy|kRequiresBody, kDefaultPropRange, - /*special parents,kids*/ 0,&gLIKids, + /*tag*/ eHTMLTag_link, + /*parent,leaf*/ kAllTags - kHeadContent, true }, { - /*tag*/ eHTMLTag_link, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gInHead,&gInHead, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kAllTags - kHeadContent, kNone, kNone, - /*special props, prop-range*/ kNonContainer|kPreferHead|kLegalOpen,kDefaultPropRange, - /*special parents,kids*/ &gInHead,0, + /*tag*/ eHTMLTag_listing, + /*parent,leaf*/ kPreformatted, false }, { - /*tag*/ eHTMLTag_listing, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kPreformatted, (kSelf|kFlowEntity), kNone, //add flowentity to fix 54993 - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_main, + /*parent,leaf*/ kBlock, false }, { - /*tag*/ eHTMLTag_main, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kBlock, (kSelf|kFlowEntity), kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_map, + /*parent,leaf*/ kSpecial, false }, { - /*tag*/ eHTMLTag_map, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kSpecial, kInlineEntity|kBlockEntity, kNone, - /*special props, prop-range*/ 0, kDefaultPropRange, - /*special parents,kids*/ 0,&gMapKids, + /*tag*/ eHTMLTag_mark, + /*parent,leaf*/ kSpecial, false }, { - /*tag*/ eHTMLTag_mark, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kSpecial, (kInlineEntity|kSelf|kFlowEntity), kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_marquee, + /*parent,leaf*/ kSpecial, false }, { - /*tag*/ eHTMLTag_marquee, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kSpecial, (kSelf|kFlowEntity), kNone, - /*special props, prop-range*/ kRequiresBody, kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_menu, + /*parent,leaf*/ kList, false }, { - /*tag*/ eHTMLTag_menu, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kList, (kSelf|kFlowEntity), kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,&gULKids, + /*tag*/ eHTMLTag_menuitem, + /*parent,leaf*/ kFlowEntity, false }, { - /*tag*/ eHTMLTag_menuitem, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kFlowEntity, kNone, kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_meta, + /*parent,leaf*/ kHeadContent, true }, { - /*tag*/ eHTMLTag_meta, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gInHead,&gInHead, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kHeadContent, kNone, kNone, - /*special props, prop-range*/ kNoStyleLeaksIn|kNonContainer, kDefaultPropRange, - /*special parents,kids*/ &gInHead,0, + /*tag*/ eHTMLTag_meter, + /*parent,leaf*/ kFormControl, false }, { - /*tag*/ eHTMLTag_meter, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kFormControl, kFlowEntity, kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_multicol, + /*parent,leaf*/ kBlock, false }, { - /*tag*/ eHTMLTag_multicol, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kBlock, kFlowEntity, kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_nav, + /*parent,leaf*/ kBlock, false }, { - /*tag*/ eHTMLTag_nav, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kBlock, (kSelf|kFlowEntity), kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_nobr, + /*parent,leaf*/ kExtensions, false }, { - /*tag*/ eHTMLTag_nobr, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kExtensions, kFlowEntity, kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_noembed, + /*parent,leaf*/ kFlowEntity, false }, { - /*tag*/ eHTMLTag_noembed, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kFlowEntity, kFlowEntity, kNone, - /*special props, prop-range*/ 0, kNoPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_noframes, + /*parent,leaf*/ kFlowEntity, false }, { - /*tag*/ eHTMLTag_noframes, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gNoframeRoot,&gNoframeRoot, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kFlowEntity, kFlowEntity, kNone, - /*special props, prop-range*/ 0, kNoPropRange, - /*special parents,kids*/ &gNoframeRoot,0, + /*tag*/ eHTMLTag_noscript, + /*parent,leaf*/ kFlowEntity|kHeadMisc, false }, { - /*tag*/ eHTMLTag_noscript, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kFlowEntity|kHeadMisc, kFlowEntity|kSelf, kNone, - /*special props, prop-range*/ 0, kNoPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_object, + /*parent,leaf*/ kSpecial, false }, { - /*tag*/ eHTMLTag_object, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kSpecial, (kFlowEntity|kSelf), kNone, - /*special props, prop-range*/ kNoStyleLeaksOut|kPreferBody,kDefaultPropRange, - /*special parents,kids*/ 0,&gContainsParam, + /*tag*/ eHTMLTag_ol, + /*parent,leaf*/ kList, false }, { - /*tag*/ eHTMLTag_ol, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gOLRootTags,&gOLRootTags, - /*autoclose starttags and endtags*/ &gOLAutoClose, &gULCloseTags, 0,0, - /*parent,incl,exclgroups*/ kList, (kFlowEntity|kSelf), kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,&gULKids, + /*tag*/ eHTMLTag_optgroup, + /*parent,leaf*/ kNone, false }, { - /*tag*/ eHTMLTag_optgroup, - /*requiredAncestor*/ eHTMLTag_select,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gOptgroupParents,&gOptgroupParents, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kNone, kNone, kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ &gOptgroupParents,&gContainsOpts, + /*tag*/ eHTMLTag_option, + /*parent,leaf*/ kNone, false }, { - /*tag*/ eHTMLTag_option, - /*requiredAncestor*/ eHTMLTag_select,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gOptgroupParents,&gOptgroupParents, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kNone, kPCDATA, kFlowEntity|kHeadMisc, - /*special props, prop-range*/ kNoStyleLeaksIn|kNoPropagate, kDefaultPropRange, - /*special parents,kids*/ &gOptgroupParents,&gContainedInOpt, + /*tag*/ eHTMLTag_output, + /*parent,leaf*/ kSpecial, false }, { - /*tag*/ eHTMLTag_output, - /*requiredAncestor*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kSpecial, (kInlineEntity|kSelf), kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_p, + /*parent,leaf*/ kBlock, false }, { - /*tag*/ eHTMLTag_p, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kBlock, kInlineEntity, kNone, //this used to contain FLOW. But it's really an inline container. - /*special props, prop-range*/ kHandleStrayTag,kDefaultPropRange, //otherwise it tries to contain things like H1..H6 - /*special parents,kids*/ 0,&gInP, + /*tag*/ eHTMLTag_param, + /*parent,leaf*/ kSpecial, true }, { - /*tag*/ eHTMLTag_param, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gParamParents,&gParamParents, - /*autoclose starttags and endtags*/ &gPAutoClose,0,0,0, - /*parent,incl,exclgroups*/ kSpecial, kNone, kNone, - /*special props, prop-range*/ kNonContainer, kNoPropRange, - /*special parents,kids*/ &gParamParents,0, + /*tag*/ eHTMLTag_plaintext, + /*parent,leaf*/ kExtensions, false }, { - /*tag*/ eHTMLTag_plaintext, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kExtensions, kCDATA, kNone, - /*special props, prop-range*/ 0, kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_pre, + /*parent,leaf*/ kBlock|kPreformatted, false }, { - /*tag*/ eHTMLTag_pre, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kBlock|kPreformatted, (kSelf|kFlowEntity), kNone, // Note: PRE is a block level element - bug 80009 - /*special props, prop-range*/ kRequiresBody, kDefaultPropRange, - /*special parents,kids*/ 0,&gPreKids, + /*tag*/ eHTMLTag_progress, + /*parent,leaf*/ kFormControl, false }, { - /*tag*/ eHTMLTag_progress, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kFormControl, kFlowEntity, kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_q, + /*parent,leaf*/ kSpecial, false }, { - /*tag*/ eHTMLTag_q, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kSpecial, (kSelf|kInlineEntity), kNone, - /*special props, prop-range*/ 0, kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_s, + /*parent,leaf*/ kFontStyle, false }, { - /*tag*/ eHTMLTag_s, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kFontStyle, (kSelf|kInlineEntity), kNone, - /*special props, prop-range*/ 0, kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_samp, + /*parent,leaf*/ kPhrase, false }, { - /*tag*/ eHTMLTag_samp, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kPhrase, (kSelf|kInlineEntity), kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_script, + /*parent,leaf*/ (kSpecial|kHeadContent), false }, { - /*tag*/ eHTMLTag_script, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ (kSpecial|kHeadContent), kCDATA, kNone, // note: this is kHeadContent since shipping this breaks things. - /*special props, prop-range*/ kNoStyleLeaksIn|kLegalOpen, kNoPropRange, - /*special parents,kids*/ 0,&gContainsText, + /*tag*/ eHTMLTag_section, + /*parent,leaf*/ kBlock, false }, { - /*tag*/ eHTMLTag_section, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kBlock, (kSelf|kFlowEntity), kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_select, + /*parent,leaf*/ kFormControl, false }, { - /*tag*/ eHTMLTag_select, - /*requiredAncestor*/ eHTMLTag_unknown, eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gInForm,&gInForm, - /*autoclose starttags and endtags*/ &gInputAutoClose,0,0,0, - /*parent,incl,exclgroups*/ kFormControl, kNone, kFlowEntity|kDLChild|kHeadMisc, // Added kHeadMisc to fix bug 287349 - /*special props, prop-range*/ kNoPropagate|kNoStyleLeaksIn|kRequiresBody, kDefaultPropRange, - /*special parents,kids*/ &gInForm,&gContainsOpts, + /*tag*/ eHTMLTag_small, + /*parent,leaf*/ kFontStyle, false }, { - /*tag*/ eHTMLTag_small, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kFontStyle, (kSelf|kInlineEntity), kNone, - /*special props, prop-range*/ 0, kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_source, + /*parent,leaf*/ kSpecial, true }, { - /*tag*/ eHTMLTag_source, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gSourceParents,&gSourceParents, - /*autoclose starttags and endtags*/ &gPAutoClose, 0, 0,0, - /*parent,incl,exclgroups*/ kSpecial, kNone, kNone, - /*special props, prop-range*/ kNonContainer,kNoPropRange, - /*special parents,kids*/ &gSourceParents,0, + /*tag*/ eHTMLTag_span, + /*parent,leaf*/ kSpecial, false }, { - - // I made span a special% tag again, (instead of inline). - // This fixes the case: <font color="blue"><p><span>text</span> - - /*tag*/ eHTMLTag_span, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kSpecial, (kInlineEntity|kSelf|kFlowEntity), kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_strike, + /*parent,leaf*/ kFontStyle, false + }, + { + /*tag*/ eHTMLTag_strong, + /*parent,leaf*/ kPhrase, false }, { - - /*tag*/ eHTMLTag_strike, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kFontStyle, (kSelf|kInlineEntity), kNone, - /*special props, prop-range*/ 0, kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_style, + /*parent,leaf*/ kAllTags - kHeadContent, false }, { - - /*tag*/ eHTMLTag_strong, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kPhrase, (kSelf|kInlineEntity), kNone, //changed this to inline per spec; fix bug 44584. - /*special props, prop-range*/ 0, kDefaultPropRange, - /*special parents,kids*/ 0,&gContainsText, + /*tag*/ eHTMLTag_sub, + /*parent,leaf*/ kSpecial, false }, { - - /*tag*/ eHTMLTag_style, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kAllTags - kHeadContent, kCDATA, kNone, - /*special props, prop-range*/ kNoStyleLeaksIn|kPreferHead|kLegalOpen, kNoPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_sup, + /*parent,leaf*/ kSpecial, false }, { - /*tag*/ eHTMLTag_sub, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kSpecial, (kSelf|kInlineEntity), kNone, - /*special props, prop-range*/ 0, kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_table, + /*parent,leaf*/ kBlock, false }, { - - /*tag*/ eHTMLTag_sup, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kSpecial, (kSelf|kInlineEntity), kNone, - /*special props, prop-range*/ 0, kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_tbody, + /*parent,leaf*/ kNone, false }, { - /*tag*/ eHTMLTag_table, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gTableRootTags,&gTableRootTags, - /*autoclose starttags and endtags*/ 0,&gTableCloseTags,0,0, - /*parent,incl,exclgroups*/ kBlock, kNone, (kSelf|kInlineEntity), - /*special props, prop-range*/ (kBadContentWatch|kNoStyleLeaksIn|kRequiresBody), 2, - /*special parents,kids*/ 0,&gTableKids, + /*tag*/ eHTMLTag_td, + /*parent,leaf*/ kNone, false }, { - /*tag*/ eHTMLTag_tbody, - /*requiredAncestor*/ eHTMLTag_table, eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gInTable,&gInTable, - /*autoclose starttags and endtags*/ &gTBodyAutoClose,0,0,0, - /*parent,incl,exclgroups*/ kNone, kNone, (kSelf|kInlineEntity), - /*special props, prop-range*/ (kNoPropagate|kBadContentWatch|kNoStyleLeaksIn|kNoStyleLeaksOut), kDefaultPropRange, - /*special parents,kids*/ &gInTable,&gTBodyKids, + /*tag*/ eHTMLTag_textarea, + /*parent,leaf*/ kFormControl, false }, { - /*tag*/ eHTMLTag_td, - /*requiredAncestor*/ eHTMLTag_table, eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gTDRootTags,&gTDRootTags, - /*autoclose starttags and endtags*/ &gTDCloseTags,&gTDCloseTags,0,&gExcludableParents, - /*parent,incl,exclgroups*/ kNone, kFlowEntity, kSelf, - /*special props, prop-range*/ kNoStyleLeaksIn|kNoStyleLeaksOut, kDefaultPropRange, - /*special parents,kids*/ &gTDRootTags,&gBodyKids, + /*tag*/ eHTMLTag_tfoot, + /*parent,leaf*/ kNone, false }, { - /*tag*/ eHTMLTag_textarea, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gInForm,&gInForm, - /*autoclose starttags and endtags*/ &gInputAutoClose,0,0,0, - /*parent,incl,exclgroups*/ kFormControl, kPCDATA, kNone, - /*special props, prop-range*/ kRequiresBody|kNoStyleLeaksIn,kDefaultPropRange, - /*special parents,kids*/ &gInForm,&gContainsText, + /*tag*/ eHTMLTag_th, + /*parent,leaf*/ kNone, false }, { - /*tag*/ eHTMLTag_tfoot, - /*requiredAncestor*/ eHTMLTag_table, eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gInTable,&gInTable, - /*autoclose starttags and endtags*/ &gTBodyAutoClose,0,0,0, - /*parent,incl,exclgroups*/ kNone, kNone, kSelf, - /*special props, prop-range*/ (kNoPropagate|kBadContentWatch|kNoStyleLeaksIn|kNoStyleLeaksOut), kNoPropRange, - /*special parents,kids*/ &gInTable,&gTableElemKids, + /*tag*/ eHTMLTag_thead, + /*parent,leaf*/ kNone, false }, { - /*tag*/ eHTMLTag_th, - /*requiredAncestor*/ eHTMLTag_table, eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gTDRootTags,&gTDRootTags, - /*autoclose starttags and endtags*/ &gTDCloseTags,&gTDCloseTags,0,0, - /*parent,incl,exclgroups*/ kNone, kFlowEntity, kSelf, - /*special props, prop-range*/ (kNoStyleLeaksIn|kNoStyleLeaksOut), kDefaultPropRange, - /*special parents,kids*/ &gTDRootTags,&gBodyKids, + /*tag*/ eHTMLTag_template, + /*parent,leaf*/ kNone, false }, { - /*tag*/ eHTMLTag_thead, - /*req-parent excl-parent*/ eHTMLTag_table,eHTMLTag_unknown, //fix bug 54840... - /*rootnodes,endrootnodes*/ &gInTable,&gInTable, - /*autoclose starttags and endtags*/ &gTBodyAutoClose,0,0,0, - /*parent,incl,exclgroups*/ kNone, kNone, kSelf, - /*special props, prop-range*/ (kNoPropagate|kBadContentWatch|kNoStyleLeaksIn|kNoStyleLeaksOut), kNoPropRange, - /*special parents,kids*/ &gInTable,&gTableElemKids, + /*tag*/ eHTMLTag_time, + /*parent,leaf*/ kPhrase, false }, { - /*tag*/ eHTMLTag_template, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kNone, kNone, kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_title, + /*parent,leaf*/ kHeadContent, false }, { - /*tag*/ eHTMLTag_time, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kPhrase, (kSelf|kInlineEntity), kNone, - /*special props, prop-range*/ 0, kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_tr, + /*parent,leaf*/ kNone, false }, { - /*tag*/ eHTMLTag_title, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gInHead,&gInHead, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kHeadContent,kPCDATA, kNone, - /*special props, prop-range*/ kNoStyleLeaksIn, kNoPropRange, - /*special parents,kids*/ &gInHead,&gContainsText, + /*tag*/ eHTMLTag_track, + /*parent,leaf*/ kSpecial, true }, { - /*tag*/ eHTMLTag_tr, - /*requiredAncestor*/ eHTMLTag_table, eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gTRParents,&gTREndParents, - /*autoclose starttags and endtags*/ &gTRCloseTags,0,0,0, - /*parent,incl,exclgroups*/ kNone, kNone, kInlineEntity, - /*special props, prop-range*/ (kBadContentWatch|kNoStyleLeaksIn|kNoStyleLeaksOut), kNoPropRange, - /*special parents,kids*/ &gTRParents,&gTRKids, + /*tag*/ eHTMLTag_tt, + /*parent,leaf*/ kFontStyle, false }, { - /*tag*/ eHTMLTag_track, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gTrackParents,&gTrackParents, - /*autoclose starttags and endtags*/ &gPAutoClose, 0, 0,0, - /*parent,incl,exclgroups*/ kSpecial, kNone, kNone, - /*special props, prop-range*/ kNonContainer,kNoPropRange, - /*special parents,kids*/ &gTrackParents,0, + /*tag*/ eHTMLTag_u, + /*parent,leaf*/ kFontStyle, false }, { - /*tag*/ eHTMLTag_tt, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kFontStyle, (kSelf|kInlineEntity), kNone, - /*special props, prop-range*/ 0, kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_ul, + /*parent,leaf*/ kList, false }, { - /*tag*/ eHTMLTag_u, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kFontStyle, (kSelf|kInlineEntity), kNone, - /*special props, prop-range*/ 0, kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_var, + /*parent,leaf*/ kPhrase, false }, { - /*tag*/ eHTMLTag_ul, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gOLRootTags,&gOLRootTags, - /*autoclose starttags and endtags*/ &gULAutoClose,&gULCloseTags,0,0, - /*parent,incl,exclgroups*/ kList, (kFlowEntity|kSelf), kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,&gULKids, + /*tag*/ eHTMLTag_video, + /*parent,leaf*/ kSpecial, false + }, + { + /*tag*/ eHTMLTag_wbr, + /*parent,leaf*/ kExtensions, true }, { - /*tag*/ eHTMLTag_var, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kPhrase, (kSelf|kInlineEntity), kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_xmp, + /*parent,leaf*/ kInlineEntity|kPreformatted, false }, { - /*tag*/ eHTMLTag_video, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0, 0, 0,0, - /*parent,incl,exclgroups*/ kSpecial, (kFlowEntity|kSelf), kNone, - /*special props, prop-range*/ 0,kDefaultPropRange, - /*special parents,kids*/ 0,&gVideoKids, + /*tag*/ eHTMLTag_text, + /*parent,leaf*/ kFlowEntity, true }, { - /*tag*/ eHTMLTag_wbr, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kExtensions, kNone, kNone, - /*special props, prop-range*/ kNonContainer|kRequiresBody,kNoPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_whitespace, + /*parent,leaf*/ kFlowEntity|kHeadMisc, true }, { - /*tag*/ eHTMLTag_xmp, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kInlineEntity|kPreformatted, kCDATA, kNone, - /*special props, prop-range*/ kNone,kDefaultPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_newline, + /*parent,leaf*/ kFlowEntity|kHeadMisc, true }, { - /*tag*/ eHTMLTag_text, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gInBody,&gInBody, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kFlowEntity, kNone, kNone, - /*special props, prop-range*/ kNonContainer|kRequiresBody,kNoPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_comment, + /*parent,leaf*/ kFlowEntity|kHeadMisc, false }, { - // Whitespace must have a parent model of kHeadMisc to ensure that we - // do the right thing for whitespace in the head section of a document. - // (i.e., it must be non-exclusively a child of the head). - - /*tag*/ eHTMLTag_whitespace, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gInBody,&gInBody, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kFlowEntity|kHeadMisc, kNone, kNone, - /*special props, prop-range*/ kNonContainer|kLegalOpen,kNoPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_entity, + /*parent,leaf*/ kFlowEntity, false }, { - // Newlines must have a parent model of kHeadMisc to ensure that we - // do the right thing for whitespace in the head section of a document. - // (i.e., it must be non-exclusively a child of the head). - - /*tag*/ eHTMLTag_newline, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gInBody,&gInBody, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kFlowEntity|kHeadMisc, kNone, kNone, - /*special props, prop-range*/ kNonContainer|kLegalOpen, kNoPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_doctypeDecl, + /*parent,leaf*/ kFlowEntity, false }, { - // Comments must have a parent model of kHeadMisc to ensure that we - // do the right thing for whitespace in the head section of a document - // (i.e., it must be non-exclusively a child of the head). - - /*tag*/ eHTMLTag_comment, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kFlowEntity|kHeadMisc, kNone, kNone, - /*special props, prop-range*/ kOmitEndTag|kLegalOpen,kNoPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_markupDecl, + /*parent,leaf*/ kFlowEntity, false + }, + { + /*tag*/ eHTMLTag_instruction, + /*parent,leaf*/ kFlowEntity, false }, { - /*tag*/ eHTMLTag_entity, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gInBody,&gInBody, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kFlowEntity, kNone, kNone, - /*special props, prop-range*/ 0, kNoPropRange, - /*special parents,kids*/ 0,0, - }, - { - /*tag*/ eHTMLTag_doctypeDecl, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kFlowEntity, kNone, kNone, - /*special props, prop-range*/ kOmitEndTag,kNoPropRange, - /*special parents,kids*/ 0,0, + /*tag*/ eHTMLTag_userdefined, + /*parent,leaf*/ (kFlowEntity|kHeadMisc), false }, - { - /*tag*/ eHTMLTag_markupDecl, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kFlowEntity, kNone, kNone, - /*special props, prop-range*/ kOmitEndTag,kNoPropRange, - /*special parents,kids*/ 0,0, - }, - { - /*tag*/ eHTMLTag_instruction, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, - /*rootnodes,endrootnodes*/ 0,0, - /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kFlowEntity, kNone, kNone, - /*special props, prop-range*/ kOmitEndTag,kNoPropRange, - /*special parents,kids*/ 0,0, - }, - { - // Userdefined tags must have a parent model of kHeadMisc to ensure that - // we do the right thing for whitespace in the head section of a document. - // (i.e., it must be non-exclusively a child of the head). - - /*tag*/ eHTMLTag_userdefined, - /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_frameset, - /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, - /*autoclose starttags and endtags*/ &gBodyAutoClose,0,0,0, - /*parent,incl,exclgroups*/ (kFlowEntity|kHeadMisc), (kInlineEntity|kSelf), kNone, // Treat userdefined as inline element - Ref bug 56245,66772 - /*special props, prop-range*/ kPreferBody, kBodyPropRange, - /*special parents,kids*/ &gInNoframes,&gBodyKids, - } }; -#ifdef DEBUG -void CheckElementTable() { +/*********************************************************************************************/ + +bool nsHTMLElement::IsContainer(eHTMLTags aChild) +{ + return !gHTMLElements[aChild].mLeaf; +} + +bool nsHTMLElement::IsMemberOf(int32_t aSet) const +{ + return TestBits(aSet,mParentBits); +} + +#ifdef DEBUG +void CheckElementTable() +{ for (eHTMLTags t = eHTMLTag_unknown; t <= eHTMLTag_userdefined; t = eHTMLTags(t + 1)) { NS_ASSERTION(gHTMLElements[t].mTagID == t, "gHTMLElements entries does match tag list."); } } #endif - -/** - * Call this to find the index of a given child, or (if not found) - * the index of its nearest synonym. - * - * @update gess 3/25/98 - * @param aTagStack -- list of open tags - * @param aTag -- tag to test for containership - * @return index of kNotFound - */ -int32_t nsHTMLElement::GetIndexOfChildOrSynonym(nsDTDContext& aContext,eHTMLTags aChildTag) { - int32_t theChildIndex=aContext.LastOf(aChildTag); - if(kNotFound==theChildIndex) { - const TagList* theSynTags=gHTMLElements[aChildTag].GetSynonymousTags(); //get the list of tags that THIS tag can close - if(theSynTags) { - theChildIndex=LastOf(aContext,*theSynTags); - } - } - return theChildIndex; -} - -/** - * - * @update gess1/21/99 - * @param - * @return - */ -bool nsHTMLElement::HasSpecialProperty(int32_t aProperty) const{ - bool result=TestBits(mSpecialProperties,aProperty); - return result; -} - -/** - * - * @update gess12/13/98 - * @param - * @return - */ -bool nsHTMLElement::IsContainer(eHTMLTags aChild) { - bool result=(eHTMLTag_unknown==aChild); - - if(!result){ - result=!TestBits(gHTMLElements[aChild].mSpecialProperties,kNonContainer); - } - return result; -} - -/** - * This tests whether all the bits in the parentbits - * are included in the given set. It may be too - * broad a question for most cases. - * - * @update gess12/13/98 - * @param - * @return - */ -bool nsHTMLElement::IsMemberOf(int32_t aSet) const{ - return TestBits(aSet,mParentBits); -} - -/** - * This tests whether all the bits in the parentbits - * are included in the given set. It may be too - * broad a question for most cases. - * - * @update gess12/13/98 - * @param - * @return - */ -bool nsHTMLElement::ContainsSet(int32_t aSet) const{ - return TestBits(mParentBits,aSet); -} - -/** - * This method determines whether the given tag closes other blocks. - * - * @update gess 12/20/99 -- added H1..H6 to this list. - * @param - * @return - */ -bool nsHTMLElement::IsBlockCloser(eHTMLTags aTag){ - bool result=false; - - if((aTag>=eHTMLTag_unknown) & (aTag<=eHTMLTag_xmp)){ - - result=(gHTMLElements[aTag].IsBlock() || - gHTMLElements[aTag].IsBlockEntity() || - (kHeading==gHTMLElements[aTag].mParentBits)); - if(!result) { - // NOBR is a block closure - Ref. Bug# 24462 - // DIR is a block closure - Ref. Bug# 25845 - // TD is a block closure - Ref. Bug# 27490 - // TR is a block closure - Ref. Bug# 26488 - // OBJECT is a block closure - Ref. Bug# 88992 - - static eHTMLTags gClosers[]={ eHTMLTag_table,eHTMLTag_tbody, - eHTMLTag_td,eHTMLTag_th, - eHTMLTag_tr,eHTMLTag_caption, - eHTMLTag_object,eHTMLTag_applet, - eHTMLTag_ol, eHTMLTag_ul, - eHTMLTag_optgroup, - eHTMLTag_nobr,eHTMLTag_dir}; - - result=FindTagInSet(aTag,gClosers,sizeof(gClosers)/sizeof(eHTMLTag_body)); - } - } - return result; -} - - -/** - * - * @update gess 01/04/99 - * @param - * @return - */ -bool nsHTMLElement::IsInlineEntity(eHTMLTags aTag){ - bool result=false; - if((aTag>=eHTMLTag_unknown) & (aTag<=eHTMLTag_xmp)){ - result=TestBits(gHTMLElements[aTag].mParentBits,kInlineEntity); - } - return result; -} - -/** - * - * @update gess 01/04/99 - * @param - * @return - */ -bool nsHTMLElement::IsFlowEntity(eHTMLTags aTag){ - bool result=false; - - if((aTag>=eHTMLTag_unknown) & (aTag<=eHTMLTag_xmp)){ - result=TestBits(gHTMLElements[aTag].mParentBits,kFlowEntity); - } - return result; -} - -/** - * - * @update gess 01/04/99 - * @param - * @return - */ -bool nsHTMLElement::IsBlockParent(eHTMLTags aTag){ - bool result=false; - if((aTag>=eHTMLTag_unknown) & (aTag<=eHTMLTag_xmp)){ - result=TestBits(gHTMLElements[aTag].mInclusionBits,kBlockEntity); - } - return result; -} - -/** - * - * @update gess 01/04/99 - * @param - * @return - */ -bool nsHTMLElement::IsInlineParent(eHTMLTags aTag){ - bool result=false; - if((aTag>=eHTMLTag_unknown) & (aTag<=eHTMLTag_xmp)){ - result=TestBits(gHTMLElements[aTag].mInclusionBits,kInlineEntity); - } - return result; -} - - -/** - * - * @update gess 01/04/99 - * @param - * @return - */ -bool nsHTMLElement::IsFlowParent(eHTMLTags aTag){ - bool result=false; - if((aTag>=eHTMLTag_unknown) & (aTag<=eHTMLTag_xmp)){ - result=TestBits(gHTMLElements[aTag].mInclusionBits,kFlowEntity); - } - return result; -} - -/** - * - * @update harishd 11/19/99 - * @param - * @return - */ -bool nsHTMLElement::IsSpecialParent(eHTMLTags aTag) const{ - bool result=false; - if(mSpecialParents) { - if(FindTagInSet(aTag,mSpecialParents->mTags,mSpecialParents->mCount)) - result=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 - */ -bool nsHTMLElement::IsSectionTag(eHTMLTags aTag){ - bool result=false; - switch(aTag){ - case eHTMLTag_html: - case eHTMLTag_frameset: - case eHTMLTag_body: - case eHTMLTag_head: - result=true; - break; - default: - result=false; - } - return result; -} - - -/** - * - * @update gess 01/04/99 - * @param - * @return - */ -bool nsHTMLElement::CanContain(eHTMLTags aParent,eHTMLTags aChild,nsDTDMode aMode){ - bool result=false; - if((aParent>=eHTMLTag_unknown) && (aParent<=eHTMLTag_userdefined)){ - result=gHTMLElements[aParent].CanContain(aChild,aMode); - } - return result; -} - -/** - * - * @update gess 01/04/99 - * @param - * @return - */ -bool nsHTMLElement::CanExclude(eHTMLTags aChild) const{ - bool result=false; - - if(gHTMLElements[aChild].HasSpecialProperty(kLegalOpen)) { - // Some tags could be opened anywhere, in the document, as they please. - return false; - } - - //Note that special kids takes precedence over exclusions... - if(mSpecialKids) { - if(FindTagInSet(aChild,mSpecialKids->mTags,mSpecialKids->mCount)) { - return false; - } - } - - if(mExclusionBits){ - if(gHTMLElements[aChild].IsMemberOf(mExclusionBits)) { - result=true; - } - } - return result; -} - -/** - * - * @update harishd 03/01/00 - * @param - * @return - */ -bool nsHTMLElement::IsExcludableParent(eHTMLTags aParent) const{ - bool result=false; - - if(!IsTextTag(mTagID)) { - if(mExcludableParents) { - const TagList* theParents=mExcludableParents; - if(FindTagInSet(aParent,theParents->mTags,theParents->mCount)) - result=true; - } - if(!result) { - // If you're a block parent make sure that you're not the - // parent of a TABLE element. ex. <table><tr><td><div><td></tr></table> - // IE & Nav. render this as table with two cells ( which I think is correct ). - // NOTE: If need arise we could use the root node to solve this problem - if(nsHTMLElement::IsBlockParent(aParent)){ - switch(mTagID) { - case eHTMLTag_caption: - case eHTMLTag_thead: - case eHTMLTag_tbody: - case eHTMLTag_tfoot: - case eHTMLTag_td: - case eHTMLTag_th: - case eHTMLTag_tr: - result=true; - default: - break; - } - } - } - } - return result; -} - -/** - * - * @update gess 01/04/99 - * @param - * @return - */ -bool nsHTMLElement::CanOmitEndTag(void) const{ - bool result=!IsContainer(mTagID); - if(!result) - result=TestBits(mSpecialProperties,kOmitEndTag); - return result; -} - -/** - * Returns whether a given tag can be a direct child of the <head> node of - * an HTML document. - * - * @param aChild The tag in question. - * @param aExclusively [out]Whether or not this tag can *only* appear in the - * head (as opposed to things like <object> which can be - either in the body or the head). - * @return Whether this tag can appear in the head. - */ -bool nsHTMLElement::IsChildOfHead(eHTMLTags aChild,bool& aExclusively) { - aExclusively = true; - - // Is this a head-only tag? - if (gHTMLElements[aChild].mParentBits & kHeadContent) { - return true; - } - - - // If not, check if it can appear in the head. - if (gHTMLElements[aChild].mParentBits & kHeadMisc) { - aExclusively = false; - return true; - } - - return false; -} - - - -/** - * - * @update gess12/13/98 - * @param - * @return - */ -bool nsHTMLElement::SectionContains(eHTMLTags aChild,bool allowDepthSearch) const { - bool result=false; - const TagList* theRootTags=gHTMLElements[aChild].GetRootTags(); - - if(theRootTags){ - if(!FindTagInSet(mTagID,theRootTags->mTags,theRootTags->mCount)){ - eHTMLTags theRootBase=theRootTags->mTags[0]; - if((eHTMLTag_unknown!=theRootBase) && (allowDepthSearch)) - result=SectionContains(theRootBase,allowDepthSearch); - } - else result=true; - } - return result; -} - -/** - * This method should be called to determine if the a tags - * hierarchy needs to be validated. - * - * @update harishd 04/19/00 - * @param - * @return - */ - -bool nsHTMLElement::ShouldVerifyHierarchy() const { - bool result=false; - - // If the tag cannot contain itself then we need to make sure that - // anywhere in the hierarchy we don't nest accidently. - // Ex: <H1><LI><H1><LI>. Inner LI has the potential of getting nested - // inside outer LI.If the tag can contain self, Ex: <A><B><A>, - // ( B can contain self )then ask the child (<A>) if it requires a containment check. - if(mTagID!=eHTMLTag_userdefined) { - result=HasSpecialProperty(kVerifyHierarchy); - } - return result; -} - -/** - * - * @update gess12/13/98 - * @param - * @return - */ -bool nsHTMLElement::IsResidualStyleTag(eHTMLTags aChild) { - bool result=false; - switch(aChild) { - case eHTMLTag_a: - case eHTMLTag_b: - case eHTMLTag_bdo: - case eHTMLTag_big: - case eHTMLTag_del: - case eHTMLTag_em: - case eHTMLTag_font: - case eHTMLTag_i: - case eHTMLTag_ins: - case eHTMLTag_q: - case eHTMLTag_s: - case eHTMLTag_small: - case eHTMLTag_strong: - case eHTMLTag_strike: - case eHTMLTag_sub: - case eHTMLTag_sup: - case eHTMLTag_tt: - case eHTMLTag_u: - result=true; - break; - - case eHTMLTag_abbr: - case eHTMLTag_acronym: - case eHTMLTag_center: - case eHTMLTag_cite: - case eHTMLTag_code: - case eHTMLTag_dfn: - case eHTMLTag_kbd: - case eHTMLTag_samp: - case eHTMLTag_span: - case eHTMLTag_var: - result=false; - default: - break; - }; - return result; -} - -/** - * - * @update gess12/13/98 - * @param - * @return - */ -bool nsHTMLElement::CanContainType(int32_t aType) const{ - int32_t answer=mInclusionBits & aType; - bool result=bool(0!=answer); - return result; -} - -/** - * - * @update gess12/13/98 - * @param - * @return - */ -bool nsHTMLElement::IsWhitespaceTag(eHTMLTags aChild) { - bool result=false; - - switch(aChild) { - case eHTMLTag_newline: - case eHTMLTag_whitespace: - result=true; - break; - default: - break; - } - return result; -} - -/** - * - * @update gess12/13/98 - * @param - * @return - */ -bool nsHTMLElement::IsTextTag(eHTMLTags aChild) { - bool result=false; - - switch(aChild) { - case eHTMLTag_text: - case eHTMLTag_entity: - case eHTMLTag_newline: - case eHTMLTag_whitespace: - result=true; - break; - default: - break; - } - return result; -} - -/** - * - * @update gess12/13/98 - * @param - * @return - */ -bool nsHTMLElement::CanContainSelf(void) const { - bool result=bool(TestBits(mInclusionBits,kSelf)!=0); - return result; -} - -/** - * This method is called to determine (once and for all) whether a start tag - * can close another tag on the stack. This method will return - * false if something prevents aParentTag from closing. - * - * @update gess 12/20/99 - * @param aContext is the tag stack we're testing against - * @param aIndex is the index of the tag we want to close - * @param aChildTag is the child we're trying to close - * @return TRUE if we can autoclose the start tag; FALSE otherwise - */ -bool nsHTMLElement::CanAutoCloseTag(nsDTDContext& aContext,int32_t aIndex, - eHTMLTags aChildTag) const{ - - int32_t thePos; - bool result = true; - eHTMLTags thePrevTag; - - for(thePos = aContext.GetCount() - 1; thePos >= aIndex; thePos--) { - thePrevTag = aContext.TagAt(thePos); - - if (thePrevTag == eHTMLTag_applet || - thePrevTag == eHTMLTag_td) { - result = false; - break; - } - } - - return result; -} - -/** - * - * @update gess 10.17.2000 - * @param - * @return - */ -eHTMLTags nsHTMLElement::GetCloseTargetForEndTag(nsDTDContext& aContext,int32_t anIndex,nsDTDMode aMode) 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) { - // Allow phrasals to close userdefined tags. bug 256731 - if(eHTMLTag_userdefined == theTag) { - continue; // We can close this. - } - - // Fixes a derivative of bug 22842... - if(CanContainType(kBlock)) { // INS/DEL can contain blocks. - if(gHTMLElements[eHTMLTags(theTag)].IsMemberOf(kBlockEntity) || - gHTMLElements[eHTMLTags(theTag)].IsMemberOf(kFlowEntity)) { - if(HasOptionalEndTag(theTag)) { - continue; // Then I can close it. - } - } - } - - // Phrasal elements can close other phrasals, along with fontstyle, - // extensions, and special tags... - if(!gHTMLElements[theTag].IsMemberOf(kSpecial | - kFontStyle | - kPhrase | - kExtensions)) { //fix bug 56665 - 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) { - // Special elements can close other specials, along with fontstyle - // extensions, and phrasal tags... - - // Added Phrasal to fix bug 26347 - if((eHTMLTag_userdefined==theTag) || - gHTMLElements[theTag].IsSpecialEntity() || - gHTMLElements[theTag].IsFontStyleEntity()|| - gHTMLElements[theTag].IsPhraseEntity() || - gHTMLElements[theTag].IsMemberOf(kExtensions)) { - continue; - } - else { - - // Fixes bug 22842... - if(CanContainType(kBlock)) { - if(gHTMLElements[eHTMLTags(theTag)].IsMemberOf(kBlockEntity) || - gHTMLElements[eHTMLTags(theTag)].IsMemberOf(kFlowEntity)) { - if(HasOptionalEndTag(theTag)) { - continue; // Then I can close it. - } - } - } - break; // It's not something I can close - } - } - else { - result=theTag; // Stop because you just found yourself on the stack - break; - } - } - } - - else if(ContainsSet(kPreformatted) || - IsMemberOf(kFormControl|kExtensions|kPreformatted)){ //bug54834... - - while((--theIndex>=anIndex) && (eHTMLTag_unknown==result)){ - eHTMLTags theTag=aContext.TagAt(theIndex); - if(theTag!=mTagID) { - if(!CanContain(theTag,aMode)) { - break; //it's not something I can close - } - } - else { - result=theTag; //stop because you just found yourself on the stack - break; - } - } - } - - else if(IsMemberOf(kList)){ - - while((--theIndex>=anIndex) && (eHTMLTag_unknown==result)){ - eHTMLTags theTag=aContext.TagAt(theIndex); - if(theTag!=mTagID) { - if(!CanContain(theTag,aMode)) { - break; //it's not something I can close - } - } - else { - result=theTag; //stop because you just found yourself on the stack - break; - } - } - } - - else if(IsResidualStyleTag(mTagID)){ - - // Before finding a close target, for the current tag, make sure - // that the tag above does not gate. - // Note: we intentionally make 2 passes: - // The first pass tries to exactly match, the 2nd pass matches the group. - - const TagList* theRootTags=gHTMLElements[mTagID].GetEndRootTags(); - int32_t theIndexCopy=theIndex; - while(--theIndex>=anIndex){ - eHTMLTags theTag=aContext.TagAt(theIndex); - if(theTag == mTagID) { - return theTag; // we found our target. - } - else if (!CanContain(theTag,aMode) || - (theRootTags && FindTagInSet(theTag,theRootTags->mTags,theRootTags->mCount))) { - // If you cannot contain this tag then - // you cannot close it either. It looks like - // the tag trying to close is misplaced. - // In the following Exs. notice the misplaced /font: - // Ex. <font><table><tr><td></font></td></tr></table. -- Ref. bug 56245 - // Ex. <font><select><option></font></select> -- Ref. bug 37618 - // Ex. <font><select></font><option></select> -- Ref. bug 98187 - return eHTMLTag_unknown; - } - } - - theIndex=theIndexCopy; - while(--theIndex>=anIndex){ - eHTMLTags theTag=aContext.TagAt(theIndex); - if(gHTMLElements[theTag].IsMemberOf(mParentBits)) { - return theTag; - } - } - } - - else if(gHTMLElements[mTagID].IsTableElement()) { - - //This fixes 57378... - //example: <TABLE><THEAD><TR><TH></THEAD> which didn't close the <THEAD> - - int32_t theLastTable=aContext.LastOf(eHTMLTag_table); - int32_t theLastOfMe=aContext.LastOf(mTagID); - if(theLastTable<theLastOfMe) { - return mTagID; - } - - } - - else if(mTagID == eHTMLTag_legend) { - while((--theIndex>=anIndex) && (eHTMLTag_unknown==result)){ - eHTMLTags theTag = aContext.TagAt(theIndex); - if (theTag == mTagID) { - result = theTag; - break; - } - - if (!CanContain(theTag, aMode)) { - break; - } - } - } - - else if (mTagID == eHTMLTag_head) { - while (--theIndex >= anIndex) { - eHTMLTags tag = aContext.TagAt(theIndex); - if (tag == eHTMLTag_html) { - // HTML gates head closing, but the head should never be the parent of - // an html tag. - break; - } - - if (tag == eHTMLTag_head) { - result = eHTMLTag_head; - break; - } - } - } - - return result; -} - - -/** - * See whether this tag can DIRECTLY contain the given child. - * @update gess12/13/98 - * @param - * @return - */ -bool nsHTMLElement::CanContain(eHTMLTags aChild,nsDTDMode aMode) const{ - - - if(IsContainer(mTagID)){ - - if(gHTMLElements[aChild].HasSpecialProperty(kLegalOpen)) { - // Some tags could be opened anywhere, in the document, as they please. - return true; - } - - if(mTagID==aChild) { - return CanContainSelf(); //not many tags can contain themselves... - } - - const TagList* theCloseTags=gHTMLElements[aChild].GetAutoCloseStartTags(); - if(theCloseTags){ - if(FindTagInSet(mTagID,theCloseTags->mTags,theCloseTags->mCount)) - return false; - } - - if(gHTMLElements[aChild].mExcludableParents) { - const TagList* theParents=gHTMLElements[aChild].mExcludableParents; - if(FindTagInSet(mTagID,theParents->mTags,theParents->mCount)) - return false; - } - - if(gHTMLElements[aChild].IsExcludableParent(mTagID)) - return false; - - if(gHTMLElements[aChild].IsBlockCloser(aChild)){ - if(nsHTMLElement::IsBlockParent(mTagID)){ - return true; - } - } - - if(nsHTMLElement::IsInlineEntity(aChild)){ - if(nsHTMLElement::IsInlineParent(mTagID)){ - return true; - } - } - - if(nsHTMLElement::IsFlowEntity(aChild)) { - if(nsHTMLElement::IsFlowParent(mTagID)){ - return true; - } - } - - if(nsHTMLElement::IsTextTag(aChild)) { - // Allow <xmp> to contain text. - if(nsHTMLElement::IsInlineParent(mTagID) || CanContainType(kCDATA)){ - return true; - } - } - - if(CanContainType(gHTMLElements[aChild].mParentBits)) { - return true; - } - - if(mSpecialKids) { - if(FindTagInSet(aChild,mSpecialKids->mTags,mSpecialKids->mCount)) { - return true; - } - } - - // Allow <p> to contain <table> only in Quirks mode, bug 43678 and bug 91927 - if (aChild == eHTMLTag_table && mTagID == eHTMLTag_p && aMode == eDTDMode_quirks) { - return true; - } - } - - return false; -} - -#ifdef DEBUG -void nsHTMLElement::DebugDumpContainment(const char* aFilename,const char* aTitle){ -} - -void nsHTMLElement::DebugDumpMembership(const char* aFilename){ -} - -void nsHTMLElement::DebugDumpContainType(const char* aFilename){ -} -#endif
--- a/parser/htmlparser/src/nsElementTable.h +++ b/parser/htmlparser/src/nsElementTable.h @@ -10,19 +10,18 @@ * */ #ifndef _NSELEMENTABLE #define _NSELEMENTABLE -#include "nsHTMLTokens.h" -#include "nsDTDUtils.h" - +#include "nsHTMLTags.h" +#include "nsIDTD.h" //********************************************************************************************* // The following ints define the standard groups of HTML elements... //********************************************************************************************* static const int kNone= 0x0; static const int kHTMLContent = 0x0001; // HEAD, (FRAMESET | BODY) @@ -54,184 +53,40 @@ static const int kBlockEntity = (kHead static const int kFlowEntity = (kBlockEntity|kInlineEntity); // %blockentity, %inlineentity static const int kAllTags = 0xffffff; //********************************************************************************************* // The following ints define the standard groups of HTML elements... //********************************************************************************************* - #ifdef DEBUG extern void CheckElementTable(); #endif /** * We're asking the question: is aTest a member of bitset. * - * @update gess 01/04/99 * @param * @return TRUE or FALSE */ inline bool TestBits(int aBitset,int aTest) { if(aTest) { int32_t result=(aBitset & aTest); return bool(result==aTest); } return false; } - -/** - * - * @update gess 01/04/99 - * @param - * @return - */ struct nsHTMLElement { - -#ifdef DEBUG - static void DebugDumpMembership(const char* aFilename); - static void DebugDumpContainment(const char* aFilename,const char* aTitle); - static void DebugDumpContainType(const char* aFilename); -#endif - - static bool IsInlineEntity(eHTMLTags aTag); - static bool IsFlowEntity(eHTMLTags aTag); - static bool IsBlockCloser(eHTMLTags aTag); - - inline bool IsBlock(void) const { - if((mTagID>=eHTMLTag_unknown) & (mTagID<=eHTMLTag_xmp)){ - return TestBits(mParentBits,kBlock); - } - return false; - } - - inline bool IsBlockEntity(void) const { - if((mTagID>=eHTMLTag_unknown) & (mTagID<=eHTMLTag_xmp)){ - return TestBits(mParentBits,kBlockEntity); - } - return false; - } - - inline bool IsSpecialEntity(void) const { - if((mTagID>=eHTMLTag_unknown) & (mTagID<=eHTMLTag_xmp)){ - return TestBits(mParentBits,kSpecial); - } - return false; - } - - inline bool IsPhraseEntity(void) const { - if((mTagID>=eHTMLTag_unknown) & (mTagID<=eHTMLTag_xmp)){ - return TestBits(mParentBits,kPhrase); - } - return false; - } - - inline bool IsFontStyleEntity(void) const { - if((mTagID>=eHTMLTag_unknown) & (mTagID<=eHTMLTag_xmp)){ - return TestBits(mParentBits,kFontStyle); - } - return false; - } - - inline bool IsTableElement(void) const { //return yes if it's a table or child of a table... - bool result=false; - - switch(mTagID) { - case eHTMLTag_table: - case eHTMLTag_thead: - case eHTMLTag_tbody: - case eHTMLTag_tfoot: - case eHTMLTag_caption: - case eHTMLTag_tr: - case eHTMLTag_td: - case eHTMLTag_th: - case eHTMLTag_col: - case eHTMLTag_colgroup: - result=true; - break; - default: - result=false; - } - return result; - } - - - static int32_t GetIndexOfChildOrSynonym(nsDTDContext& aContext,eHTMLTags aChildTag); - - const TagList* GetSynonymousTags(void) const {return mSynonymousTags;} - const TagList* GetRootTags(void) const {return mRootNodes;} - const TagList* GetEndRootTags(void) const {return mEndRootNodes;} - const TagList* GetAutoCloseStartTags(void) const {return mAutocloseStart;} - const TagList* GetAutoCloseEndTags(void) const {return mAutocloseEnd;} - eHTMLTags GetCloseTargetForEndTag(nsDTDContext& aContext,int32_t anIndex,nsDTDMode aMode) const; - - const TagList* GetSpecialChildren(void) const {return mSpecialKids;} - const TagList* GetSpecialParents(void) const {return mSpecialParents;} - bool IsMemberOf(int32_t aType) const; - bool ContainsSet(int32_t aType) const; - bool CanContainType(int32_t aType) const; - - bool CanContain(eHTMLTags aChild,nsDTDMode aMode) const; - bool CanExclude(eHTMLTags aChild) const; - bool CanOmitEndTag(void) const; - bool CanContainSelf(void) const; - bool CanAutoCloseTag(nsDTDContext& aContext,int32_t aIndex,eHTMLTags aTag) const; - bool HasSpecialProperty(int32_t aProperty) const; - bool IsSpecialParent(eHTMLTags aTag) const; - bool IsExcludableParent(eHTMLTags aParent) const; - bool SectionContains(eHTMLTags aTag,bool allowDepthSearch) const; - bool ShouldVerifyHierarchy() const; - - static bool CanContain(eHTMLTags aParent,eHTMLTags aChild,nsDTDMode aMode); - static bool IsContainer(eHTMLTags aTag) ; - static bool IsResidualStyleTag(eHTMLTags aTag) ; - static bool IsTextTag(eHTMLTags aTag); - static bool IsWhitespaceTag(eHTMLTags aTag); - - static bool IsBlockParent(eHTMLTags aTag); - static bool IsInlineParent(eHTMLTags aTag); - static bool IsFlowParent(eHTMLTags aTag); - static bool IsSectionTag(eHTMLTags aTag); - static bool IsChildOfHead(eHTMLTags aTag,bool& aExclusively) ; eHTMLTags mTagID; - eHTMLTags mRequiredAncestor; - eHTMLTags mExcludingAncestor; //If set, the presence of the excl-ancestor prevents this from opening. - const TagList* mRootNodes; //These are the tags above which you many not autoclose a START tag - const TagList* mEndRootNodes; //These are the tags above which you many not autoclose an END tag - const TagList* mAutocloseStart; //these are the start tags that you can automatically close with this START tag - const TagList* mAutocloseEnd; //these are the start tags that you can automatically close with this END tag - const TagList* mSynonymousTags; //These are morally equivalent; an end tag for one can close a start tag for another (like <Hn>) - const TagList* mExcludableParents; //These are the TAGS that cannot contain you int mParentBits; //defines groups that can contain this element - int mInclusionBits; //defines parental and containment rules - int mExclusionBits; //defines things you CANNOT contain - int mSpecialProperties; //used for various special purposes... - uint32_t mPropagateRange; //tells us how far a parent is willing to prop. badly formed children - const TagList* mSpecialParents; //These are the special tags that contain this tag (directly) - const TagList* mSpecialKids; //These are the extra things you can contain + bool mLeaf; + + static bool IsContainer(eHTMLTags aTag); }; extern const nsHTMLElement gHTMLElements[]; -//special property bits... -static const int kPreferBody = 0x0001; //this kHeadMisc tag prefers to be in the body if there isn't an explicit <head> -static const int kOmitEndTag = 0x0002; //safely ignore end tag -static const int kLegalOpen = 0x0004; //Lets BODY, TITLE, SCRIPT to reopen -static const int kNoPropagate = 0x0008; //If set, this tag won't propagate as a child -static const int kBadContentWatch = 0x0010; - -static const int kNoStyleLeaksIn = 0x0020; -static const int kNoStyleLeaksOut = 0x0040; - -static const int kMustCloseSelf = 0x0080; -static const int kSaveMisplaced = 0x0100; //If set, then children this tag can't contain are pushed onto the misplaced stack -static const int kNonContainer = 0x0200; //If set, then this tag is not a container. -static const int kHandleStrayTag = 0x0400; //If set, we automatically open a start tag -static const int kRequiresBody = 0x0800; //If set, then in case of no BODY one will be opened up immediately. -static const int kVerifyHierarchy = 0x1000; //If set, check to see if the tag is a child or a sibling.. -static const int kPreferHead = 0x2000; //This kHeadMisc tag prefers to be in the head if there isn't an explicit <body> - #endif
--- a/parser/htmlparser/src/nsExpatDriver.cpp +++ b/parser/htmlparser/src/nsExpatDriver.cpp @@ -1284,46 +1284,37 @@ nsExpatDriver::WillBuildModel(const CPar // XML must detect invalid character convertion aParserContext.mScanner->OverrideReplacementCharacter(0xffff); return mInternalState; } NS_IMETHODIMP -nsExpatDriver::BuildModel(nsITokenizer* aTokenizer, - bool,// aCountLines, - const nsCString*)// aCharsetPtr) +nsExpatDriver::BuildModel(nsITokenizer* aTokenizer, nsIContentSink* aSink) { return mInternalState; } NS_IMETHODIMP nsExpatDriver::DidBuildModel(nsresult anErrorCode) { mOriginalSink = nullptr; mSink = nullptr; mExtendedSink = nullptr; return NS_OK; } NS_IMETHODIMP -nsExpatDriver::WillTokenize(bool aIsFinalChunk, - nsTokenAllocator* aTokenAllocator) +nsExpatDriver::WillTokenize(bool aIsFinalChunk) { mIsFinalChunk = aIsFinalChunk; return NS_OK; } -NS_IMETHODIMP -nsExpatDriver::DidTokenize(bool aIsFinalChunk) -{ - return NS_OK; -} - NS_IMETHODIMP_(void) nsExpatDriver::Terminate() { // XXX - not sure what happens to the unparsed data. if (mExpatParser) { XML_StopParser(mExpatParser, XML_FALSE); } mInternalState = NS_ERROR_HTMLPARSER_STOPPARSING; @@ -1338,75 +1329,16 @@ nsExpatDriver::GetType() NS_IMETHODIMP_(nsDTDMode) nsExpatDriver::GetMode() const { return eDTDMode_full_standards; } /*************************** Unused methods **********************************/ -NS_IMETHODIMP_(CToken*) -nsExpatDriver::PushTokenFront(CToken* aToken) -{ - return 0; -} - -NS_IMETHODIMP_(CToken*) -nsExpatDriver::PushToken(CToken* aToken) -{ - return 0; -} - -NS_IMETHODIMP_(CToken*) -nsExpatDriver::PopToken(void) -{ - return 0; -} - -NS_IMETHODIMP_(CToken*) -nsExpatDriver::PeekToken(void) -{ - return 0; -} - -NS_IMETHODIMP_(CToken*) -nsExpatDriver::GetTokenAt(int32_t anIndex) -{ - return 0; -} - -NS_IMETHODIMP_(int32_t) -nsExpatDriver::GetCount(void) -{ - return 0; -} - -NS_IMETHODIMP_(nsTokenAllocator*) -nsExpatDriver::GetTokenAllocator(void) -{ - return 0; -} - -NS_IMETHODIMP_(void) -nsExpatDriver::PrependTokens(nsDeque& aDeque) -{ -} - -NS_IMETHODIMP -nsExpatDriver::CopyState(nsITokenizer* aTokenizer) -{ - return NS_OK; -} - -nsresult -nsExpatDriver::HandleToken(CToken* aToken) -{ - return NS_OK; -} - NS_IMETHODIMP_(bool) nsExpatDriver::IsContainer(int32_t aTag) const { return true; } NS_IMETHODIMP_(bool) nsExpatDriver::CanContain(int32_t aParent,int32_t aChild) const
--- a/parser/htmlparser/src/nsExpatDriver.h +++ b/parser/htmlparser/src/nsExpatDriver.h @@ -62,18 +62,16 @@ public: const PRUnichar* aPubid); nsresult HandleUnparsedEntityDecl(const PRUnichar* aEntityName, const PRUnichar* aBase, const PRUnichar* aSysid, const PRUnichar* aPubid, const PRUnichar* aNotationName); private: - nsresult HandleToken(CToken* aToken); - // Load up an external stream to get external entity information nsresult OpenInputStreamFromExternalDTD(const PRUnichar* aFPIStr, const PRUnichar* aURLStr, const PRUnichar* aBaseURL, nsIInputStream** aStream, nsAString& aAbsURL); /**
--- a/parser/htmlparser/src/nsHTMLTokenizer.cpp +++ b/parser/htmlparser/src/nsHTMLTokenizer.cpp @@ -11,22 +11,18 @@ * This file contains the implementation of a tokenizer to tokenize an HTML * document. It attempts to do so, making tradeoffs between compatibility with * older parsers and the SGML specification. Note that most of the real * "tokenization" takes place in nsHTMLTokens.cpp. */ #include "nsIAtom.h" #include "nsHTMLTokenizer.h" -#include "nsScanner.h" -#include "nsElementTable.h" -#include "nsReadableUtils.h" -#include "nsUnicharUtils.h" #include "nsParserConstants.h" -#include "mozilla/Likely.h" +#include "nsIHTMLContentSink.h" /************************************************************************ And now for the main class -- nsHTMLTokenizer... ************************************************************************/ /** * Satisfy the nsISupports interface. */ @@ -38,59 +34,26 @@ NS_IMPL_ISUPPORTS1(nsHTMLTokenizer, nsIT * @param aParseMode The current mode the document is in (quirks, etc.) * @param aDocType The document type of the current document * @param aCommand What we are trying to do (view-source, parse a fragment, etc.) */ nsHTMLTokenizer::nsHTMLTokenizer(nsDTDMode aParseMode, eParserDocType aDocType, eParserCommands aCommand, uint32_t aFlags) - : mTokenDeque(0), mFlags(aFlags) { - if (aParseMode == eDTDMode_full_standards || - aParseMode == eDTDMode_almost_standards) { - mFlags |= NS_IPARSER_FLAG_STRICT_MODE; - } else if (aParseMode == eDTDMode_quirks) { - mFlags |= NS_IPARSER_FLAG_QUIRKS_MODE; - } else if (aParseMode == eDTDMode_autodetect) { - mFlags |= NS_IPARSER_FLAG_AUTO_DETECT_MODE; - } else { - mFlags |= NS_IPARSER_FLAG_UNKNOWN_MODE; - } - - if (aDocType == ePlainText) { - mFlags |= NS_IPARSER_FLAG_PLAIN_TEXT; - } else if (aDocType == eXML) { - mFlags |= NS_IPARSER_FLAG_XML; - } else if (aDocType == eHTML_Quirks || - aDocType == eHTML_Strict) { - mFlags |= NS_IPARSER_FLAG_HTML; - } - - mFlags |= aCommand == eViewSource - ? NS_IPARSER_FLAG_VIEW_SOURCE - : NS_IPARSER_FLAG_VIEW_NORMAL; - - NS_ASSERTION(!(mFlags & NS_IPARSER_FLAG_XML) || - (mFlags & NS_IPARSER_FLAG_VIEW_SOURCE), - "Why isn't this XML document going through our XML parser?"); - - mTokenAllocator = nullptr; - mTokenScanPos = 0; + // TODO Assert about:blank-ness. + MOZ_ASSERT(!(aFlags & NS_IPARSER_FLAG_XML)); } /** * The destructor ensures that we don't leak any left over tokens. */ nsHTMLTokenizer::~nsHTMLTokenizer() { - if (mTokenDeque.GetSize()) { - CTokenDeallocator theDeallocator(mTokenAllocator->GetArenaPool()); - mTokenDeque.ForEach(theDeallocator); - } } /*static*/ uint32_t nsHTMLTokenizer::GetFlags(const nsIContentSink* aSink) { uint32_t flags = 0; nsCOMPtr<nsIHTMLContentSink> sink = do_QueryInterface(const_cast<nsIContentSink*>(aSink)); @@ -103,1095 +66,31 @@ nsHTMLTokenizer::GetFlags(const nsIConte sink->IsEnabled(eHTMLTag_script, &enabled); if (enabled) { flags |= NS_IPARSER_FLAG_SCRIPT_ENABLED; } } return flags; } -/******************************************************************* - Here begins the real working methods for the tokenizer. - *******************************************************************/ - -/** - * Adds a token onto the end of the deque if aResult is a successful result. - * Otherwise, this function frees aToken and sets it to nullptr. - * - * @param aToken The token that wants to be added. - * @param aResult The error code that will be used to determine if we actually - * want to push this token. - * @param aDeque The deque we want to push aToken onto. - * @param aTokenAllocator The allocator we use to free aToken in case aResult - * is not a success code. - */ -/* static */ -void -nsHTMLTokenizer::AddToken(CToken*& aToken, - nsresult aResult, - nsDeque* aDeque, - nsTokenAllocator* aTokenAllocator) -{ - if (aToken && aDeque) { - if (NS_SUCCEEDED(aResult)) { - aDeque->Push(aToken); - } else { - IF_FREE(aToken, aTokenAllocator); - } - } -} - -/** - * Retrieve a pointer to the global token recycler... - * - * @return Pointer to recycler (or null) - */ -nsTokenAllocator* -nsHTMLTokenizer::GetTokenAllocator() -{ - return mTokenAllocator; -} - -/** - * This method provides access to the topmost token in the tokenDeque. - * The token is not really removed from the list. - * - * @return Pointer to token - */ -CToken* -nsHTMLTokenizer::PeekToken() -{ - return (CToken*)mTokenDeque.PeekFront(); -} - -/** - * This method provides access to the topmost token in the tokenDeque. - * The token is really removed from the list; if the list is empty we return 0. - * - * @return Pointer to token or nullptr - */ -CToken* -nsHTMLTokenizer::PopToken() -{ - return (CToken*)mTokenDeque.PopFront(); -} - - -/** - * Pushes a token onto the front of our deque such that the next call to - * PopToken() or PeekToken() will return that token. - * - * @param theToken The next token to be processed - * @return theToken - */ -CToken* -nsHTMLTokenizer::PushTokenFront(CToken* theToken) +nsresult +nsHTMLTokenizer::WillTokenize(bool aIsFinalChunk) { - mTokenDeque.PushFront(theToken); - return theToken; -} - -/** - * Pushes a token onto the deque. - * - * @param theToken the new token. - * @return theToken - */ -CToken* -nsHTMLTokenizer::PushToken(CToken* theToken) -{ - mTokenDeque.Push(theToken); - return theToken; -} - -/** - * Returns the size of the deque. - * - * @return The number of remaining tokens. - */ -int32_t -nsHTMLTokenizer::GetCount() -{ - return mTokenDeque.GetSize(); -} - -/** - * Allows access to an arbitrary token in the deque. The accessed token is left - * in the deque. - * - * @param anIndex The index of the target token. Token 0 would be the same as - * the result of a call to PeekToken() - * @return The requested token. - */ -CToken* -nsHTMLTokenizer::GetTokenAt(int32_t anIndex) -{ - return (CToken*)mTokenDeque.ObjectAt(anIndex); -} - -/** - * This method is part of the "sandwich" that occurs when we want to tokenize - * a document. This prepares us to be able to tokenize properly. - * - * @param aIsFinalChunk Whether this is the last chunk of data that we will - * get to see. - * @param aTokenAllocator The token allocator to use for this document. - * @return Our success in setting up. - */ -nsresult -nsHTMLTokenizer::WillTokenize(bool aIsFinalChunk, - nsTokenAllocator* aTokenAllocator) -{ - mTokenAllocator = aTokenAllocator; - mIsFinalChunk = aIsFinalChunk; - - // Cause ScanDocStructure to search from here for new tokens... - mTokenScanPos = mTokenDeque.GetSize(); - return NS_OK; -} - -/** - * Pushes all of the tokens in aDeque onto the front of our deque so they - * get processed before any other tokens. - * - * @param aDeque The deque with the tokens in it. - */ -void -nsHTMLTokenizer::PrependTokens(nsDeque& aDeque) -{ - int32_t aCount = aDeque.GetSize(); - - for (int32_t anIndex = 0; anIndex < aCount; ++anIndex) { - CToken* theToken = (CToken*)aDeque.Pop(); - PushTokenFront(theToken); - } -} - -/** - * Copies the state flags from aTokenizer into this tokenizer. This is used - * to pass information around between the main tokenizer and tokenizers - * created for document.write() calls. - * - * @param aTokenizer The tokenizer with more information in it. - * @return NS_OK - */ -nsresult -nsHTMLTokenizer::CopyState(nsITokenizer* aTokenizer) -{ - if (aTokenizer) { - mFlags = ((nsHTMLTokenizer*)aTokenizer)->mFlags; - } - return NS_OK; } /** - * This is a utilty method for ScanDocStructure, which finds a given - * tag in the stack. The return value is meant to be used with - * nsDeque::ObjectAt() on aTagStack. - * - * @param aTag -- the ID of the tag we're seeking - * @param aTagStack -- the stack to be searched - * @return index position of tag in stack if found, otherwise kNotFound - */ -static int32_t -FindLastIndexOfTag(eHTMLTags aTag, nsDeque &aTagStack) -{ - int32_t theCount = aTagStack.GetSize(); - - while (0 < theCount) { - CHTMLToken* theToken = (CHTMLToken*)aTagStack.ObjectAt(--theCount); - if (theToken) { - eHTMLTags theTag = (eHTMLTags)theToken->GetTypeID(); - if (theTag == aTag) { - return theCount; - } - } - } - - return kNotFound; -} - -/** - * This method scans the sequence of tokens to determine whether or not the - * tag structure of the document is well formed. In well formed cases, we can - * skip doing residual style handling and allow inlines to contain block-level - * elements. - * - * @param aFinalChunk Is unused. - * @return Success (currently, this function cannot fail). - */ -nsresult nsHTMLTokenizer::ScanDocStructure(bool aFinalChunk) -{ - nsresult result = NS_OK; - if (!mTokenDeque.GetSize()) { - return result; - } - - CHTMLToken* theToken = (CHTMLToken*)mTokenDeque.ObjectAt(mTokenScanPos); - - // Start by finding the first start tag that hasn't been reviewed. - while (mTokenScanPos > 0) { - if (theToken) { - eHTMLTokenTypes theType = eHTMLTokenTypes(theToken->GetTokenType()); - if (theType == eToken_start && - theToken->GetContainerInfo() == eFormUnknown) { - break; - } - } - theToken = (CHTMLToken*)mTokenDeque.ObjectAt(--mTokenScanPos); - } - - // Now that we know where to start, let's walk through the - // tokens to see which are well-formed. Stop when you run out - // of fresh tokens. - - nsDeque theStack(0); - nsDeque tempStack(0); - int32_t theStackDepth = 0; - // Don't bother if we get ridiculously deep. - static const int32_t theMaxStackDepth = 200; - - while (theToken && theStackDepth < theMaxStackDepth) { - eHTMLTokenTypes theType = eHTMLTokenTypes(theToken->GetTokenType()); - eHTMLTags theTag = (eHTMLTags)theToken->GetTypeID(); - - if (nsHTMLElement::IsContainer(theTag)) { // Bug 54117 - bool theTagIsBlock = gHTMLElements[theTag].IsMemberOf(kBlockEntity); - bool theTagIsInline = theTagIsBlock - ? false - : gHTMLElements[theTag].IsMemberOf(kInlineEntity); - - if (theTagIsBlock || theTagIsInline || eHTMLTag_table == theTag) { - switch(theType) { - case eToken_start: - { - if (gHTMLElements[theTag].ShouldVerifyHierarchy()) { - int32_t earlyPos = FindLastIndexOfTag(theTag, theStack); - if (earlyPos != kNotFound) { - // Uh-oh, we've found a tag that is not allowed to nest at - // all. Mark the previous one and all of its children as - // malformed to increase our chances of doing RS handling - // on all of them. We want to do this for cases such as: - // <a><div><a></a></div></a>. - // Note that we have to iterate through all of the chilren - // of the original malformed tag to protect against: - // <a><font><div><a></a></div></font></a>, so that the <font> - // is allowed to contain the <div>. - // XXX What about <a><span><a>, where the second <a> closes - // the <span>? - nsDequeIterator it(theStack, earlyPos), end(theStack.End()); - while (it < end) { - CHTMLToken *theMalformedToken = - static_cast<CHTMLToken*>(it++); - - theMalformedToken->SetContainerInfo(eMalformed); - } - } - } - - theStack.Push(theToken); - ++theStackDepth; - } - break; - case eToken_end: - { - CHTMLToken *theLastToken = - static_cast<CHTMLToken*>(theStack.Peek()); - if (theLastToken) { - if (theTag == theLastToken->GetTypeID()) { - theStack.Pop(); // Yank it for real - theStackDepth--; - theLastToken->SetContainerInfo(eWellFormed); - } else { - // This token wasn't what we expected it to be! We need to - // go searching for its real start tag on our stack. Each - // tag in between the end tag and start tag must be malformed - - if (FindLastIndexOfTag(theTag, theStack) != kNotFound) { - // Find theTarget in the stack, marking each (malformed!) - // tag in our way. - theStack.Pop(); // Pop off theLastToken for real. - do { - theLastToken->SetContainerInfo(eMalformed); - tempStack.Push(theLastToken); - theLastToken = static_cast<CHTMLToken*>(theStack.Pop()); - } while (theLastToken && theTag != theLastToken->GetTypeID()); - // XXX The above test can confuse two different userdefined - // tags. - - NS_ASSERTION(theLastToken, - "FindLastIndexOfTag lied to us!" - " We couldn't find theTag on theStack"); - theLastToken->SetContainerInfo(eMalformed); - - // Great, now push all of the other tokens back onto the - // stack to preserve the general structure of the document. - // Note that we don't push the target token back onto the - // the stack (since it was just closed). - while (tempStack.GetSize() != 0) { - theStack.Push(tempStack.Pop()); - } - } - } - } - } - break; - default: - break; - } - } - } - - theToken = (CHTMLToken*)mTokenDeque.ObjectAt(++mTokenScanPos); - } - - return result; -} - -/** - * This method is called after we're done tokenizing a chunk of data. - * - * @param aFinalChunk Tells us if this was the last chunk of data. - * @return Error result. - */ -nsresult -nsHTMLTokenizer::DidTokenize(bool aFinalChunk) -{ - return ScanDocStructure(aFinalChunk); -} - -/** * This method is repeatedly called by the tokenizer. * Each time, we determine the kind of token we're about to * read, and then we call the appropriate method to handle * that token type. * * @param aScanner The source of our input. * @param aFlushTokens An OUT parameter to tell the caller whether it should * process our queued tokens up to now (e.g., when we * reach a <script>). * @return Success or error */ nsresult nsHTMLTokenizer::ConsumeToken(nsScanner& aScanner, bool& aFlushTokens) { - PRUnichar theChar; - CToken* theToken = nullptr; - - nsresult result = aScanner.Peek(theChar); - - switch(result) { - case kEOF: - // Tell our caller that'we finished. - return result; - - case NS_OK: - default: - if (!(mFlags & NS_IPARSER_FLAG_PLAIN_TEXT)) { - if (kLessThan == theChar) { - return ConsumeTag(theChar, theToken, aScanner, aFlushTokens); - } else if (kAmpersand == theChar) { - return ConsumeEntity(theChar, theToken, aScanner); - } - } - - if (kCR == theChar || kLF == theChar) { - return ConsumeNewline(theChar, theToken, aScanner); - } else { - if (!nsCRT::IsAsciiSpace(theChar)) { - if (theChar != '\0') { - result = ConsumeText(theToken, aScanner); - } else { - // Skip the embedded null char. Fix bug 64098. - aScanner.GetChar(theChar); - } - break; - } - result = ConsumeWhitespace(theChar, theToken, aScanner); - } - break; - } - - return result; -} - -/** - * This method is called just after a "<" has been consumed - * and we know we're at the start of some kind of tagged - * element. We don't know yet if it's a tag or a comment. - * - * @param aChar is the last char read - * @param aToken is the out arg holding our new token (the function allocates - * the return token using mTokenAllocator). - * @param aScanner represents our input source - * @param aFlushTokens is an OUT parameter use to tell consumers to flush - * the current tokens after processing the current one. - * @return error code. - */ -nsresult -nsHTMLTokenizer::ConsumeTag(PRUnichar aChar, - CToken*& aToken, - nsScanner& aScanner, - bool& aFlushTokens) -{ - PRUnichar theNextChar, oldChar; - nsresult result = aScanner.Peek(aChar, 1); - - if (NS_OK == result) { - switch (aChar) { - case kForwardSlash: - result = aScanner.Peek(theNextChar, 2); - - if (NS_OK == result) { - // Get the original "<" (we've already seen it with a Peek) - aScanner.GetChar(oldChar); - - // XML allows non ASCII tag names, consume this as an end tag. This - // is needed to make XML view source work - bool isXML = !!(mFlags & NS_IPARSER_FLAG_XML); - if (nsCRT::IsAsciiAlpha(theNextChar) || - kGreaterThan == theNextChar || - (isXML && !nsCRT::IsAscii(theNextChar))) { - result = ConsumeEndTag(aChar, aToken, aScanner); - } else { - result = ConsumeComment(aChar, aToken, aScanner); - } - } - - break; - - case kExclamation: - result = aScanner.Peek(theNextChar, 2); - - if (NS_OK == result) { - // Get the original "<" (we've already seen it with a Peek) - aScanner.GetChar(oldChar); - - if (kMinus == theNextChar || kGreaterThan == theNextChar) { - result = ConsumeComment(aChar, aToken, aScanner); - } else { - result = ConsumeSpecialMarkup(aChar, aToken, aScanner); - } - } - break; - - case kQuestionMark: - // It must be a processing instruction... - // Get the original "<" (we've already seen it with a Peek) - aScanner.GetChar(oldChar); - result = ConsumeProcessingInstruction(aChar, aToken, aScanner); - break; - - default: - // XML allows non ASCII tag names, consume this as a start tag. - bool isXML = !!(mFlags & NS_IPARSER_FLAG_XML); - if (nsCRT::IsAsciiAlpha(aChar) || - (isXML && !nsCRT::IsAscii(aChar))) { - // Get the original "<" (we've already seen it with a Peek) - aScanner.GetChar(oldChar); - result = ConsumeStartTag(aChar, aToken, aScanner, aFlushTokens); - } else { - // We are not dealing with a tag. So, don't consume the original - // char and leave the decision to ConsumeText(). - result = ConsumeText(aToken, aScanner); - } - } - } - - // Last ditch attempt to make sure we don't lose data. - if (kEOF == result && !aScanner.IsIncremental()) { - // Whoops, we don't want to lose any data! Consume the rest as text. - // This normally happens for either a trailing < or </ - result = ConsumeText(aToken, aScanner); - } - - return result; -} - -/** - * This method is called just after we've consumed a start or end - * tag, and we now have to consume its attributes. - * - * @param aChar is the last char read - * @param aToken is the start or end tag that "owns" these attributes. - * @param aScanner represents our input source - * @return Error result. - */ -nsresult -nsHTMLTokenizer::ConsumeAttributes(PRUnichar aChar, - CToken* aToken, - nsScanner& aScanner) -{ - bool done = false; - nsresult result = NS_OK; - int16_t theAttrCount = 0; - - nsTokenAllocator* theAllocator = this->GetTokenAllocator(); - - while (!done && result == NS_OK) { - CAttributeToken* theToken = - static_cast<CAttributeToken*> - (theAllocator->CreateTokenOfType(eToken_attribute, - eHTMLTag_unknown)); - if (MOZ_LIKELY(theToken != nullptr)) { - // Tell the new token to finish consuming text... - result = theToken->Consume(aChar, aScanner, mFlags); - - if (NS_SUCCEEDED(result)) { - ++theAttrCount; - AddToken((CToken*&)theToken, result, &mTokenDeque, theAllocator); - } else { - IF_FREE(theToken, mTokenAllocator); - // Bad attribute returns shouldn't propagate out. - if (NS_ERROR_HTMLPARSER_BADATTRIBUTE == result) { - result = NS_OK; - } - } - } - else { - result = NS_ERROR_OUT_OF_MEMORY; - } - -#ifdef DEBUG - if (NS_SUCCEEDED(result)) { - int32_t newline = 0; - aScanner.SkipWhitespace(newline); - NS_ASSERTION(newline == 0, - "CAttribute::Consume() failed to collect all the newlines!"); - } -#endif - if (NS_SUCCEEDED(result)) { - result = aScanner.Peek(aChar); - if (NS_SUCCEEDED(result)) { - if (aChar == kGreaterThan) { // You just ate the '>' - aScanner.GetChar(aChar); // Skip the '>' - done = true; - } else if (aChar == kLessThan) { - aToken->SetInError(true); - done = true; - } - } - } - } - - if (NS_FAILED(result)) { - aToken->SetInError(true); - - if (!aScanner.IsIncremental()) { - result = NS_OK; - } - } - - aToken->SetAttributeCount(theAttrCount); - return result; + return kEOF; } - -/** - * This method consumes a start tag and all of its attributes. - * - * @param aChar The last character read from the scanner. - * @param aToken The OUT parameter that holds our resulting token. (allocated - * by the function using mTokenAllocator - * @param aScanner Our source of data - * @param aFlushTokens is an OUT parameter use to tell consumers to flush - * the current tokens after processing the current one. - * @return Error result. - */ -nsresult -nsHTMLTokenizer::ConsumeStartTag(PRUnichar aChar, - CToken*& aToken, - nsScanner& aScanner, - bool& aFlushTokens) -{ - // Remember this for later in case you have to unwind... - int32_t theDequeSize = mTokenDeque.GetSize(); - nsresult result = NS_OK; - - nsTokenAllocator* theAllocator = this->GetTokenAllocator(); - aToken = theAllocator->CreateTokenOfType(eToken_start, eHTMLTag_unknown); - NS_ENSURE_TRUE(aToken, NS_ERROR_OUT_OF_MEMORY); - - // Tell the new token to finish consuming text... - result = aToken->Consume(aChar, aScanner, mFlags); - - if (NS_SUCCEEDED(result)) { - AddToken(aToken, result, &mTokenDeque, theAllocator); - - eHTMLTags theTag = (eHTMLTags)aToken->GetTypeID(); - - // Good. Now, let's see if the next char is ">". - // If so, we have a complete tag, otherwise, we have attributes. - result = aScanner.Peek(aChar); - if (NS_FAILED(result)) { - aToken->SetInError(true); - - // Don't return early here so we can create a text and end token for - // the special <iframe>, <script> and similar tags down below. - result = NS_OK; - } else { - if (kGreaterThan != aChar) { // Look for a '>' - result = ConsumeAttributes(aChar, aToken, aScanner); - } else { - aScanner.GetChar(aChar); - } - } - - /* Now that that's over with, we have one more problem to solve. - In the case that we just read a <SCRIPT> or <STYLE> tags, we should go and - consume all the content itself. - But XML doesn't treat these tags differently, so we shouldn't if the - document is XML. - */ - if (NS_SUCCEEDED(result) && !(mFlags & NS_IPARSER_FLAG_XML)) { - bool isCDATA = gHTMLElements[theTag].CanContainType(kCDATA); - bool isPCDATA = eHTMLTag_textarea == theTag || - eHTMLTag_title == theTag; - - // XXX This is an evil hack, we should be able to handle these properly - // in the DTD. - if ((eHTMLTag_iframe == theTag && - (mFlags & NS_IPARSER_FLAG_FRAMES_ENABLED)) || - (eHTMLTag_noframes == theTag && - (mFlags & NS_IPARSER_FLAG_FRAMES_ENABLED)) || - (eHTMLTag_noscript == theTag && - (mFlags & NS_IPARSER_FLAG_SCRIPT_ENABLED)) || - (eHTMLTag_noembed == theTag)) { - isCDATA = true; - } - - // Plaintext contains CDATA, but it's special, so we handle it - // differently than the other CDATA elements - if (eHTMLTag_plaintext == theTag) { - isCDATA = false; - - // Note: We check in ConsumeToken() for this flag, and if we see it - // we only construct text tokens (which is what we want). - mFlags |= NS_IPARSER_FLAG_PLAIN_TEXT; - } - - - if (isCDATA || isPCDATA) { - bool done = false; - nsDependentString endTagName(nsHTMLTags::GetStringValue(theTag)); - - CToken* text = - theAllocator->CreateTokenOfType(eToken_text, eHTMLTag_text); - NS_ENSURE_TRUE(text, NS_ERROR_OUT_OF_MEMORY); - - CTextToken* textToken = static_cast<CTextToken*>(text); - - if (isCDATA) { - result = textToken->ConsumeCharacterData(theTag != eHTMLTag_script, - aScanner, - endTagName, - mFlags, - done); - - // Only flush tokens for <script>, to give ourselves more of a - // chance of allowing inlines to contain blocks. - aFlushTokens = done && theTag == eHTMLTag_script; - } else if (isPCDATA) { - // Title is consumed conservatively in order to not regress - // bug 42945 - result = textToken->ConsumeParsedCharacterData( - theTag == eHTMLTag_textarea, - theTag == eHTMLTag_title, - aScanner, - endTagName, - mFlags, - done); - - // Note: we *don't* set aFlushTokens here. - } - - // We want to do this unless result is kEOF, in which case we will - // simply unwind our stack and wait for more data anyway. - if (kEOF != result) { - AddToken(text, NS_OK, &mTokenDeque, theAllocator); - CToken* endToken = nullptr; - - if (NS_SUCCEEDED(result) && done) { - PRUnichar theChar; - // Get the < - result = aScanner.GetChar(theChar); - NS_ASSERTION(NS_SUCCEEDED(result) && theChar == kLessThan, - "CTextToken::Consume*Data is broken!"); -#ifdef DEBUG - // Ensure we have a / - PRUnichar tempChar; // Don't change non-debug vars in debug-only code - result = aScanner.Peek(tempChar); - NS_ASSERTION(NS_SUCCEEDED(result) && tempChar == kForwardSlash, - "CTextToken::Consume*Data is broken!"); -#endif - result = ConsumeEndTag(PRUnichar('/'), endToken, aScanner); - if (!(mFlags & NS_IPARSER_FLAG_VIEW_SOURCE) && - NS_SUCCEEDED(result)) { - // If ConsumeCharacterData returned a success result (and - // we're not in view source), then we want to make sure that - // we're going to execute this script (since the result means - // that we've found an end tag that satisfies all of the right - // conditions). - endToken->SetInError(false); - } - } else if (result == kFakeEndTag && - !(mFlags & NS_IPARSER_FLAG_VIEW_SOURCE)) { - result = NS_OK; - endToken = theAllocator->CreateTokenOfType(eToken_end, theTag, - endTagName); - AddToken(endToken, result, &mTokenDeque, theAllocator); - if (MOZ_LIKELY(endToken != nullptr)) { - endToken->SetInError(true); - } - else { - result = NS_ERROR_OUT_OF_MEMORY; - } - } else if (result == kFakeEndTag) { - // If we are here, we are both faking having seen the end tag - // and are in view-source. - result = NS_OK; - } - } else { - IF_FREE(text, mTokenAllocator); - } - } - } - - // This code is confusing, so pay attention. - // If you're here, it's because we were in the midst of consuming a start - // tag but ran out of data (not in the stream, but in this *part* of the - // stream. For simplicity, we have to unwind our input. Therefore, we pop - // and discard any new tokens we've queued this round. Later we can get - // smarter about this. - if (NS_FAILED(result)) { - while (mTokenDeque.GetSize()>theDequeSize) { - CToken* theToken = (CToken*)mTokenDeque.Pop(); - IF_FREE(theToken, mTokenAllocator); - } - } - } else { - IF_FREE(aToken, mTokenAllocator); - } - - return result; -} - -/** - * This method consumes an end tag and any "attributes" that may come after it. - * - * @param aChar The last character read from the scanner. - * @param aToken The OUT parameter that holds our resulting token. - * @param aScanner Our source of data - * @return Error result - */ -nsresult -nsHTMLTokenizer::ConsumeEndTag(PRUnichar aChar, - CToken*& aToken, - nsScanner& aScanner) -{ - // Get the "/" (we've already seen it with a Peek) - aScanner.GetChar(aChar); - - nsTokenAllocator* theAllocator = this->GetTokenAllocator(); - aToken = theAllocator->CreateTokenOfType(eToken_end, eHTMLTag_unknown); - NS_ENSURE_TRUE(aToken, NS_ERROR_OUT_OF_MEMORY); - - // Remember this for later in case you have to unwind... - int32_t theDequeSize = mTokenDeque.GetSize(); - nsresult result = NS_OK; - - // Tell the new token to finish consuming text... - result = aToken->Consume(aChar, aScanner, mFlags); - AddToken(aToken, result, &mTokenDeque, theAllocator); - if (NS_FAILED(result)) { - // Note that this early-return here is safe because we have not yet - // added any of our tokens to the queue (AddToken only adds the token if - // result is a success), so we don't need to fall through. - return result; - } - - result = aScanner.Peek(aChar); - if (NS_FAILED(result)) { - aToken->SetInError(true); - - // Note: We know here that the scanner is not incremental since if - // this peek fails, then we've already masked over a kEOF coming from - // the Consume() call above.