LCOV - code coverage report
Current view: directory - parser/htmlparser/src - CNavDTD.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1113 508 45.6 %
Date: 2012-06-02 Functions: 67 44 65.7 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* vim: set sw=2 ts=2 et tw=78: */
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is mozilla.org code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Netscape Communications Corporation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      27                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #include "mozilla/Util.h"
      40                 : 
      41                 : #include "nsDebug.h"
      42                 : #include "nsIAtom.h"
      43                 : #include "CNavDTD.h"
      44                 : #include "nsHTMLTokens.h"
      45                 : #include "nsCRT.h"
      46                 : #include "nsParser.h"
      47                 : #include "nsIHTMLContentSink.h"
      48                 : #include "nsScanner.h"
      49                 : #include "prenv.h"
      50                 : #include "prtypes.h"
      51                 : #include "prio.h"
      52                 : #include "plstr.h"
      53                 : #include "nsDTDUtils.h"
      54                 : #include "nsHTMLTokenizer.h"
      55                 : #include "nsParserNode.h"
      56                 : #include "nsHTMLEntities.h"
      57                 : #include "nsLinebreakConverter.h"
      58                 : #include "nsIFormProcessor.h"
      59                 : #include "nsTArray.h"
      60                 : #include "nsReadableUtils.h"
      61                 : #include "nsUnicharUtils.h"
      62                 : #include "prmem.h"
      63                 : #include "nsIServiceManager.h"
      64                 : #include "nsParserConstants.h"
      65                 : 
      66                 : using namespace mozilla;
      67                 : 
      68                 : /*
      69                 :  * Ignore kFontStyle and kPhrase tags when the stack is deep, bug 58917.
      70                 :  */
      71                 : #define FONTSTYLE_IGNORE_DEPTH (MAX_REFLOW_DEPTH * 80 / 100)
      72                 : #define PHRASE_IGNORE_DEPTH    (MAX_REFLOW_DEPTH * 90 / 100)
      73                 : 
      74                 : static NS_DEFINE_CID(kFormProcessorCID, NS_FORMPROCESSOR_CID);
      75                 : 
      76                 : #ifdef DEBUG
      77                 : static const  char kNullToken[] = "Error: Null token given";
      78                 : static const  char kInvalidTagStackPos[] = "Error: invalid tag stack position";
      79                 : #endif
      80                 : 
      81                 : #include "nsElementTable.h"
      82                 : 
      83                 : // Some flags for use by the DTD.
      84                 : #define NS_DTD_FLAG_NONE                   0x00000000
      85                 : #define NS_DTD_FLAG_HAS_OPEN_HEAD          0x00000001
      86                 : #define NS_DTD_FLAG_HAS_OPEN_BODY          0x00000002
      87                 : #define NS_DTD_FLAG_HAS_OPEN_FORM          0x00000004
      88                 : #define NS_DTD_FLAG_HAS_EXPLICIT_HEAD      0x00000008
      89                 : #define NS_DTD_FLAG_HAD_BODY               0x00000010
      90                 : #define NS_DTD_FLAG_HAD_FRAMESET           0x00000020
      91                 : #define NS_DTD_FLAG_ENABLE_RESIDUAL_STYLE  0x00000040
      92                 : #define NS_DTD_FLAG_ALTERNATE_CONTENT      0x00000080 // NOFRAMES, NOSCRIPT
      93                 : #define NS_DTD_FLAG_MISPLACED_CONTENT      0x00000100
      94                 : #define NS_DTD_FLAG_IN_MISPLACED_CONTENT   0x00000200
      95                 : #define NS_DTD_FLAG_STOP_PARSING           0x00000400
      96                 : 
      97                 : #define NS_DTD_FLAG_HAS_MAIN_CONTAINER     (NS_DTD_FLAG_HAD_BODY |            \
      98                 :                                             NS_DTD_FLAG_HAD_FRAMESET)
      99                 : 
     100              56 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CNavDTD)
     101              28 :   NS_INTERFACE_MAP_ENTRY(nsIDTD)
     102               0 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDTD)
     103               0 : NS_INTERFACE_MAP_END
     104                 : 
     105              56 : NS_IMPL_CYCLE_COLLECTING_ADDREF(CNavDTD)
     106              56 : NS_IMPL_CYCLE_COLLECTING_RELEASE(CNavDTD)
     107                 : 
     108            1464 : NS_IMPL_CYCLE_COLLECTION_1(CNavDTD, mSink)
     109                 : 
     110              28 : CNavDTD::CNavDTD()
     111                 :   : mMisplacedContent(0),
     112                 :     mTokenAllocator(0),
     113                 :     mBodyContext(new nsDTDContext()),
     114                 :     mTempContext(0),
     115                 :     mCountLines(true),
     116                 :     mTokenizer(0),
     117                 :     mDTDMode(eDTDMode_quirks),
     118                 :     mDocType(eHTML_Quirks),
     119                 :     mParserCommand(eViewNormal),
     120                 :     mLineNumber(1),
     121                 :     mOpenMapCount(0),
     122                 :     mHeadContainerPosition(-1),
     123              56 :     mFlags(NS_DTD_FLAG_NONE)
     124                 : {
     125              28 : }
     126                 : 
     127              84 : CNavDTD::~CNavDTD()
     128                 : {
     129              28 :   delete mBodyContext;
     130              28 :   delete mTempContext;
     131             112 : }
     132                 : 
     133                 : NS_IMETHODIMP
     134              28 : CNavDTD::WillBuildModel(const CParserContext& aParserContext,
     135                 :                         nsITokenizer* aTokenizer,
     136                 :                         nsIContentSink* aSink)
     137                 : {
     138              28 :   nsresult result = NS_OK;
     139                 : 
     140              28 :   mFilename = aParserContext.mScanner->GetFilename();
     141              28 :   mFlags = NS_DTD_FLAG_ENABLE_RESIDUAL_STYLE;
     142              28 :   mLineNumber = 1;
     143              28 :   mDTDMode = aParserContext.mDTDMode;
     144              28 :   mParserCommand = aParserContext.mParserCommand;
     145              28 :   mMimeType = aParserContext.mMimeType;
     146              28 :   mDocType = aParserContext.mDocType;
     147              28 :   mTokenizer = aTokenizer;
     148              28 :   mBodyContext->SetNodeAllocator(&mNodeAllocator);
     149                 : 
     150              28 :   if (!aParserContext.mPrevContext && aSink) {
     151                 : 
     152              28 :     if (!mSink) {
     153              28 :       mSink = do_QueryInterface(aSink, &result);
     154              28 :       if (NS_FAILED(result)) {
     155               0 :         mFlags |= NS_DTD_FLAG_STOP_PARSING;
     156               0 :         return result;
     157                 :       }
     158                 :     }
     159                 : 
     160              28 :     mFlags |= nsHTMLTokenizer::GetFlags(aSink);
     161                 : 
     162                 :   }
     163                 : 
     164              28 :   return result;
     165                 : }
     166                 : 
     167                 : NS_IMETHODIMP
     168              56 : CNavDTD::BuildModel(nsITokenizer* aTokenizer,
     169                 :                     bool aCountLines,
     170                 :                     const nsCString*)
     171                 : {
     172              56 :   NS_PRECONDITION(mBodyContext != nsnull,
     173                 :                   "Create a context before calling build model");
     174                 : 
     175              56 :   nsresult result = NS_OK;
     176                 : 
     177              56 :   if (!aTokenizer) {
     178               0 :     return NS_OK;
     179                 :   }
     180                 : 
     181              56 :   nsITokenizer* const oldTokenizer = mTokenizer;
     182                 : 
     183              56 :   mCountLines     = aCountLines;
     184              56 :   mTokenizer      = aTokenizer;
     185              56 :   mTokenAllocator = mTokenizer->GetTokenAllocator();
     186                 :   
     187              56 :   if (!mSink) {
     188                 :     return (mFlags & NS_DTD_FLAG_STOP_PARSING)
     189                 :            ? NS_ERROR_HTMLPARSER_STOPPARSING
     190               0 :            : result;
     191                 :   }
     192                 : 
     193              56 :   if (mBodyContext->GetCount() == 0) {
     194                 :     CToken* tempToken;
     195              28 :     if (ePlainText == mDocType) {
     196                 :       tempToken =
     197               0 :         mTokenAllocator->CreateTokenOfType(eToken_start, eHTMLTag_pre);
     198               0 :       if (tempToken) {
     199               0 :         mTokenizer->PushTokenFront(tempToken);
     200                 :       }
     201                 :     }
     202                 : 
     203                 :     // Always open a body if frames are disabled.
     204              28 :     if (!(mFlags & NS_IPARSER_FLAG_FRAMES_ENABLED)) {
     205                 :       tempToken =
     206                 :         mTokenAllocator->CreateTokenOfType(eToken_start,
     207                 :                                            eHTMLTag_body,
     208               0 :                                            NS_LITERAL_STRING("body"));
     209               0 :       if (tempToken) {
     210               0 :         mTokenizer->PushTokenFront(tempToken);
     211                 :       }
     212                 :     }
     213                 : 
     214                 :     // If the content model is empty, then begin by opening <html>.
     215              28 :     CStartToken* theToken = (CStartToken*)mTokenizer->GetTokenAt(0);
     216              28 :     if (theToken) {
     217              25 :       eHTMLTags theTag = (eHTMLTags)theToken->GetTypeID();
     218              25 :       eHTMLTokenTypes theType = eHTMLTokenTypes(theToken->GetTokenType());
     219              25 :       if (theTag != eHTMLTag_html || theType != eToken_start) {
     220                 :         tempToken =
     221                 :           mTokenAllocator->CreateTokenOfType(eToken_start,
     222                 :                                              eHTMLTag_html,
     223              25 :                                              NS_LITERAL_STRING("html"));
     224              25 :         if (tempToken) {
     225              25 :           mTokenizer->PushTokenFront(tempToken);
     226                 :         }
     227                 :       }
     228                 :     } else {
     229                 :       tempToken =
     230                 :         mTokenAllocator->CreateTokenOfType(eToken_start,
     231                 :                                            eHTMLTag_html,
     232               3 :                                            NS_LITERAL_STRING("html"));
     233               3 :       if (tempToken) {
     234               3 :         mTokenizer->PushTokenFront(tempToken);
     235                 :       }
     236                 :     }
     237                 :   }
     238                 : 
     239            2502 :   while (NS_SUCCEEDED(result)) {
     240            2446 :     if (!(mFlags & NS_DTD_FLAG_STOP_PARSING)) {
     241            2446 :       CToken* theToken = mTokenizer->PopToken();
     242            2446 :       if (!theToken) {
     243              56 :         break;
     244                 :       }
     245            2390 :       result = HandleToken(theToken);
     246                 :     } else {
     247               0 :       result = NS_ERROR_HTMLPARSER_STOPPARSING;
     248               0 :       break;
     249                 :     }
     250                 : 
     251            2390 :     if (NS_ERROR_HTMLPARSER_INTERRUPTED == mSink->DidProcessAToken()) {
     252                 :       // The content sink has requested that DTD interrupt processing tokens
     253                 :       // We need to make sure that an interruption does not override
     254                 :       // a request to block the parser.
     255               0 :       if (NS_SUCCEEDED(result)) {
     256               0 :         result = NS_ERROR_HTMLPARSER_INTERRUPTED;
     257               0 :         break;
     258                 :       }
     259                 :     }
     260                 :   }
     261                 : 
     262              56 :   mTokenizer = oldTokenizer;
     263              56 :   return result;
     264                 : }
     265                 : 
     266                 : nsresult
     267               3 : CNavDTD::BuildNeglectedTarget(eHTMLTags aTarget,
     268                 :                               eHTMLTokenTypes aType)
     269                 : { 
     270               3 :   NS_ASSERTION(mTokenizer, "tokenizer is null! unable to build target.");
     271               3 :   NS_ASSERTION(mTokenAllocator, "unable to create tokens without an allocator.");
     272               3 :   if (!mTokenizer || !mTokenAllocator) {
     273               0 :     return NS_OK;
     274                 :   }
     275                 : 
     276               3 :   CToken* target = mTokenAllocator->CreateTokenOfType(aType, aTarget);
     277               3 :   NS_ENSURE_TRUE(target, NS_ERROR_OUT_OF_MEMORY);
     278               3 :   mTokenizer->PushTokenFront(target);
     279                 :   // Also, BuildModel
     280                 :   // doesn't seem to care about the charset, and at this point we have no idea
     281                 :   // what the charset was, so 0 can and must suffice.
     282               3 :   return BuildModel(mTokenizer, mCountLines, 0);
     283                 : }
     284                 : 
     285                 : NS_IMETHODIMP
     286              28 : CNavDTD::DidBuildModel(nsresult anErrorCode)
     287                 : {
     288              28 :   nsresult result = NS_OK;
     289                 : 
     290              28 :   if (mSink) {
     291              28 :     if (NS_OK == anErrorCode) {
     292              28 :       if (!(mFlags & NS_DTD_FLAG_HAS_MAIN_CONTAINER)) {
     293                 :         // This document is not a frameset document, however, it did not contain
     294                 :         // a body tag either. So, make one!. Note: Body tag is optional per spec..
     295                 :         // Also note: We ignore the return value of BuildNeglectedTarget, we
     296                 :         // can't reasonably respond to errors (or requests to block) at this
     297                 :         // point in the parsing process.
     298               3 :         BuildNeglectedTarget(eHTMLTag_body, eToken_start);
     299                 :       }
     300              28 :       if (mFlags & NS_DTD_FLAG_MISPLACED_CONTENT) {
     301                 :         // Looks like the misplaced contents are not processed yet.
     302                 :         // Here is our last chance to handle the misplaced content.
     303                 : 
     304                 :         // Keep track of the top index.
     305               0 :         PRInt32 topIndex = mBodyContext->mContextTopIndex;
     306                 :         
     307                 :         // Loop until we've really consumed all of our misplaced content.
     308               0 :         do {
     309               0 :           mFlags &= ~NS_DTD_FLAG_MISPLACED_CONTENT; 
     310                 : 
     311                 :           // mContextTopIndex refers to the misplaced content's legal parent index.
     312               0 :           result = HandleSavedTokens(mBodyContext->mContextTopIndex);
     313               0 :           if (NS_FAILED(result)) {
     314               0 :             NS_ERROR("Bug in the DTD");
     315               0 :             break;
     316                 :           }
     317                 : 
     318                 :           // If we start handling misplaced content while handling misplaced
     319                 :           // content, mContextTopIndex gets modified. However, this new index
     320                 :           // necessarily points to the middle of a closed tag (since we close
     321                 :           // new tags after handling the misplaced content). So we restore the
     322                 :           // insertion point after every iteration.
     323               0 :           mBodyContext->mContextTopIndex = topIndex;
     324                 :         } while (mFlags & NS_DTD_FLAG_MISPLACED_CONTENT);
     325                 : 
     326               0 :         mBodyContext->mContextTopIndex = -1; 
     327                 :       }
     328                 : 
     329                 :       // Now let's disable style handling to save time when closing remaining
     330                 :       // stack members.
     331              28 :       mFlags &= ~NS_DTD_FLAG_ENABLE_RESIDUAL_STYLE;
     332             137 :       while (mBodyContext->GetCount() > 0) { 
     333              81 :         result = CloseContainersTo(mBodyContext->Last(), false);
     334              81 :         NS_ENSURE_SUCCESS(result, result);
     335                 :       } 
     336                 :     } else {
     337                 :       // If you're here, then an error occurred, but we still have nodes on the stack.
     338                 :       // At a minimum, we should grab the nodes and recycle them.
     339                 :       // Just to be correct, we'll also recycle the nodes.
     340               0 :       while (mBodyContext->GetCount() > 0) { 
     341               0 :         nsEntryStack* theChildStyles = 0;
     342               0 :         nsCParserNode* theNode = mBodyContext->Pop(theChildStyles);
     343               0 :         IF_DELETE(theChildStyles, &mNodeAllocator);
     344               0 :         IF_FREE(theNode, &mNodeAllocator);
     345                 :       } 
     346                 :     }
     347                 : 
     348                 :     // Now make sure the misplaced content list is empty,
     349                 :     // by forcefully recycling any tokens we might find there.
     350              28 :     CToken* theToken = 0;
     351              56 :     while ((theToken = (CToken*)mMisplacedContent.Pop())) {
     352               0 :       IF_FREE(theToken, mTokenAllocator);
     353                 :     }
     354                 :   }
     355                 : 
     356              28 :   return result;
     357                 : }
     358                 : 
     359                 : NS_IMETHODIMP_(void) 
     360               0 : CNavDTD::Terminate() 
     361                 : { 
     362               0 :   mFlags |= NS_DTD_FLAG_STOP_PARSING; 
     363               0 : }
     364                 : 
     365                 : 
     366                 : NS_IMETHODIMP_(PRInt32) 
     367             240 : CNavDTD::GetType() 
     368                 : { 
     369             240 :   return NS_IPARSER_FLAG_HTML; 
     370                 : }
     371                 : 
     372                 : NS_IMETHODIMP_(nsDTDMode)
     373              28 : CNavDTD::GetMode() const
     374                 : {
     375              28 :   return mDTDMode;
     376                 : }
     377                 : 
     378                 : /**
     379                 :  * Text and some tags require a body when they're added, this function returns
     380                 :  * true for those tags.
     381                 :  *
     382                 :  * @param aToken The current token that we care about.
     383                 :  * @param aTokenizer A tokenizer that we can get the tags attributes off of.
     384                 :  * @return true if aToken does indeed force the body to open.
     385                 :  */
     386                 : static bool
     387              54 : DoesRequireBody(CToken* aToken, nsITokenizer* aTokenizer)
     388                 : {
     389              54 :   bool result = false;
     390                 : 
     391              54 :   if (aToken) {
     392              54 :     eHTMLTags theTag = (eHTMLTags)aToken->GetTypeID();
     393              54 :     if (gHTMLElements[theTag].HasSpecialProperty(kRequiresBody)) {
     394              25 :       if (theTag == eHTMLTag_input) {
     395                 :         // IE & Nav4x opens up a body for type=text - Bug 66985
     396                 :         // XXXbz but we don't want to open one for <input> with no
     397                 :         // type attribute?  That's pretty whack.
     398               0 :         PRInt32 ac = aToken->GetAttributeCount();
     399               0 :         for(PRInt32 i = 0; i < ac; ++i) {
     400                 :           CAttributeToken* attr = static_cast<CAttributeToken*>
     401               0 :                                              (aTokenizer->GetTokenAt(i));
     402               0 :           const nsSubstring& name = attr->GetKey();
     403               0 :           const nsAString& value = attr->GetValue();
     404                 :           // XXXbz note that this stupid case-sensitive comparison is
     405                 :           // actually depended on by sites...
     406               0 :           if ((name.EqualsLiteral("type") || 
     407               0 :                name.EqualsLiteral("TYPE"))    
     408                 :               && 
     409               0 :               !(value.EqualsLiteral("hidden") || 
     410               0 :               value.EqualsLiteral("HIDDEN"))) {
     411               0 :             result = true; 
     412               0 :             break;
     413                 :           }
     414                 :         }
     415                 :       } else {
     416              25 :         result = true;
     417                 :       }
     418                 :     }
     419                 :   }
     420                 :  
     421              54 :   return result;
     422                 : }
     423                 : 
     424                 : static bool
     425               0 : ValueIsHidden(const nsAString& aValue)
     426                 : {
     427                 :   // Having to deal with whitespace here sucks, but we have to match
     428                 :   // what the content sink does.
     429               0 :   nsAutoString str(aValue);
     430               0 :   str.Trim("\n\r\t\b");
     431               0 :   return str.LowerCaseEqualsLiteral("hidden");
     432                 : }
     433                 : 
     434                 : // Check whether aToken corresponds to a <input type="hidden"> tag.  The token
     435                 : // must be a start tag token for an <input>.  This must be called at a point
     436                 : // when all the attributes for the input are still in the tokenizer.
     437                 : static bool
     438               0 : IsHiddenInput(CToken* aToken, nsITokenizer* aTokenizer)
     439                 : {
     440               0 :   NS_PRECONDITION(eHTMLTokenTypes(aToken->GetTokenType()) == eToken_start,
     441                 :                   "Must be start token");
     442               0 :   NS_PRECONDITION(eHTMLTags(aToken->GetTypeID()) == eHTMLTag_input,
     443                 :                   "Must be <input> tag");
     444                 :   
     445               0 :   PRInt32 ac = aToken->GetAttributeCount();
     446               0 :   NS_ASSERTION(ac <= aTokenizer->GetCount(),
     447                 :                "Not enough tokens in the tokenizer");
     448                 :   // But we don't really trust ourselves to get that right
     449               0 :   ac = NS_MIN(ac, aTokenizer->GetCount());
     450                 :   
     451               0 :   for (PRInt32 i = 0; i < ac; ++i) {
     452               0 :     NS_ASSERTION(eHTMLTokenTypes(aTokenizer->GetTokenAt(i)->GetTokenType()) ==
     453                 :                    eToken_attribute, "Unexpected token type");
     454                 :     // Again, we're not sure we actually manage to guarantee that
     455               0 :     if (eHTMLTokenTypes(aTokenizer->GetTokenAt(i)->GetTokenType()) !=
     456                 :         eToken_attribute) {
     457               0 :       break;
     458                 :     }
     459                 :     
     460                 :     CAttributeToken* attrToken =
     461               0 :       static_cast<CAttributeToken*>(aTokenizer->GetTokenAt(i));
     462               0 :     if (!attrToken->GetKey().LowerCaseEqualsLiteral("type")) {
     463               0 :       continue;
     464                 :     }
     465                 : 
     466               0 :     return ValueIsHidden(attrToken->GetValue());
     467                 :   }
     468                 : 
     469               0 :   return false;    
     470                 : }
     471                 : 
     472                 : /**
     473                 :  * Returns whether or not there is a tag of type aType open on aContext.
     474                 :  */
     475                 : static bool
     476               0 : HasOpenTagOfType(PRInt32 aType, const nsDTDContext& aContext)
     477                 : {
     478               0 :   PRInt32 count = aContext.GetCount();
     479                 : 
     480               0 :   while (--count >= 0) {
     481               0 :     if (gHTMLElements[aContext.TagAt(count)].IsMemberOf(aType)) {
     482               0 :       return true;
     483                 :     }
     484                 :   }
     485                 : 
     486               0 :   return false;
     487                 : }
     488                 : 
     489                 : nsresult
     490            2415 : CNavDTD::HandleToken(CToken* aToken)
     491                 : {
     492            2415 :   if (!aToken) {
     493               0 :     return NS_OK;
     494                 :   }
     495                 : 
     496            2415 :   nsresult        result   = NS_OK;
     497            2415 :   CHTMLToken*     theToken = static_cast<CHTMLToken*>(aToken);
     498            2415 :   eHTMLTokenTypes theType  = eHTMLTokenTypes(theToken->GetTokenType());
     499            2415 :   eHTMLTags       theTag   = (eHTMLTags)theToken->GetTypeID();
     500                 : 
     501            2415 :   aToken->SetLineNumber(mLineNumber);
     502                 : 
     503            2415 :   if (mCountLines) {
     504            2415 :     mLineNumber += aToken->GetNewlineCount();
     505                 :   }
     506                 : 
     507            2415 :   if (mFlags & NS_DTD_FLAG_MISPLACED_CONTENT) {
     508                 :     // Included TD & TH to fix Bug# 20797
     509                 :     static eHTMLTags gLegalElements[] = {
     510                 :       eHTMLTag_table, eHTMLTag_thead, eHTMLTag_tbody,
     511                 :       eHTMLTag_tr, eHTMLTag_td, eHTMLTag_th, eHTMLTag_tfoot
     512                 :     };
     513                 :     // Don't even try processing misplaced tokens if we're already
     514                 :     // handling misplaced content. See bug 269095
     515               0 :     if (mFlags & NS_DTD_FLAG_IN_MISPLACED_CONTENT) {
     516               0 :       PushIntoMisplacedStack(theToken);
     517               0 :       return NS_OK;
     518                 :     }
     519                 : 
     520               0 :     eHTMLTags theParentTag = mBodyContext->Last();
     521               0 :     if (FindTagInSet(theTag, gLegalElements,
     522               0 :                      ArrayLength(gLegalElements)) ||
     523               0 :         (gHTMLElements[theParentTag].CanContain(theTag, mDTDMode) &&
     524                 :          // Here's a problem.  If theTag is legal in here, we don't move it
     525                 :          // out.  So if we're moving stuff out of here, the parent of theTag
     526                 :          // gets closed at this point.  But some things are legal
     527                 :          // _everywhere_ and hence would effectively close out misplaced
     528                 :          // content in tables.  This is undesirable, so treat them as
     529                 :          // illegal here so they'll be shipped out with their parents and
     530                 :          // siblings.  See bug 40855 for an explanation (that bug was for
     531                 :          // comments, but the same issues arise with whitespace, newlines,
     532                 :          // noscript, etc).  Script is special, though.  Shipping it out
     533                 :          // breaks document.write stuff.  See bug 243064.
     534               0 :          (!gHTMLElements[theTag].HasSpecialProperty(kLegalOpen) ||
     535                 :           theTag == eHTMLTag_script)) ||
     536                 :         (theTag == eHTMLTag_input && theType == eToken_start &&
     537                 :          FindTagInSet(theParentTag, gLegalElements,
     538               0 :                       ArrayLength(gLegalElements)) &&
     539               0 :          IsHiddenInput(theToken, mTokenizer))) {
     540                 :       // Reset the state since all the misplaced tokens are about to get
     541                 :       // handled.
     542               0 :       mFlags &= ~NS_DTD_FLAG_MISPLACED_CONTENT;
     543                 : 
     544               0 :       result = HandleSavedTokens(mBodyContext->mContextTopIndex);
     545               0 :       NS_ENSURE_SUCCESS(result, result);
     546                 : 
     547               0 :       mBodyContext->mContextTopIndex = -1;
     548                 :     } else {
     549               0 :       PushIntoMisplacedStack(theToken);
     550               0 :       return result;
     551                 :     }
     552                 :   }
     553                 : 
     554                 :   /*
     555                 :    * This section of code is used to "move" misplaced content from one location
     556                 :    * in our document model to another. (Consider what would happen if we found a
     557                 :    * <P> tag in the head.) To move content, we throw it onto the
     558                 :    * misplacedcontent deque until we can deal with it.
     559                 :    */
     560            2415 :   switch(theTag) {
     561                 :     case eHTMLTag_html:
     562                 :     case eHTMLTag_noframes:
     563                 :     case eHTMLTag_script:
     564                 :     case eHTMLTag_doctypeDecl:
     565                 :     case eHTMLTag_instruction:
     566              53 :       break;
     567                 : 
     568                 :     default:
     569            2362 :       if (!gHTMLElements[eHTMLTag_html].SectionContains(theTag, false)) {
     570            2334 :         if (!(mFlags & (NS_DTD_FLAG_HAS_MAIN_CONTAINER |
     571            2334 :                         NS_DTD_FLAG_ALTERNATE_CONTENT))) {
     572                 :           // For bug examples from this code, see bugs: 18928, 20989.
     573                 :           // At this point we know the body/frameset aren't open.
     574                 :           // If the child belongs in the head, then handle it (which may open
     575                 :           // the head); otherwise, push it onto the misplaced stack.
     576                 : 
     577             279 :           bool isExclusive = false;
     578                 :           bool theChildBelongsInHead =
     579             279 :             gHTMLElements[eHTMLTag_head].IsChildOfHead(theTag, isExclusive);
     580             604 :           if (theChildBelongsInHead &&
     581             200 :               !isExclusive &&
     582             125 :               !gHTMLElements[theTag].HasSpecialProperty(kPreferHead)) {
     583             250 :             if (mMisplacedContent.GetSize() == 0 &&
     584             125 :                 (!gHTMLElements[theTag].HasSpecialProperty(kPreferBody) ||
     585                 :                  (mFlags & NS_DTD_FLAG_HAS_EXPLICIT_HEAD))) {
     586                 :               // This tag can either be in the body or the head. Since
     587                 :               // there is no indication that the body should be open,
     588                 :               // put this token in the head.
     589             125 :               break;
     590                 :             }
     591                 : 
     592                 :             // Otherwise, we have received some indication that the body is
     593                 :             // "open", so push this token onto the misplaced content stack.
     594               0 :             theChildBelongsInHead = false;
     595                 :           }
     596                 : 
     597             154 :           if (!theChildBelongsInHead) {
     598              79 :             eHTMLTags top = mBodyContext->Last();
     599              79 :             NS_ASSERTION(top != eHTMLTag_userdefined,
     600                 :                          "Userdefined tags should act as leaves in the head");
     601             104 :             if (top != eHTMLTag_html && top != eHTMLTag_head &&
     602              25 :                 gHTMLElements[top].CanContain(theTag, mDTDMode)) {
     603                 :               // Some tags (such as <object> and <script>) are opened in the
     604                 :               // head and allow other non-head content to be children.
     605                 :               // Note: Userdefined tags in the head act like leaves.
     606              25 :               break;
     607                 :             }
     608                 : 
     609                 :             // If you're here then we found a child of the body that was out of
     610                 :             // place.  We're going to move it to the body by storing it
     611                 :             // temporarily on the misplaced stack.  However, in quirks mode, a
     612                 :             // few tags request, ambiguosly, for a BODY. - Bugs 18928, 24204.-
     613              54 :             PushIntoMisplacedStack(aToken);
     614                 : 
     615              54 :             if (IsAlternateTag(theTag)) {
     616                 :               // These tags' contents are consumed as CDATA. If we simply
     617                 :               // pushed them on the misplaced content stack, the CDATA
     618                 :               // contents would force us to open a body, which could be
     619                 :               // wrong. So we collect the whole tag as misplaced in one
     620                 :               // gulp. Note that the tokenizer guarantees that there will
     621                 :               // be an end tag.
     622               0 :               CToken *current = aToken;
     623               0 :               while (current->GetTokenType() != eToken_end ||
     624               0 :                      current->GetTypeID() != theTag) {
     625               0 :                 current = static_cast<CToken *>(mTokenizer->PopToken());
     626               0 :                 NS_ASSERTION(current, "The tokenizer is not creating good "
     627                 :                                       "alternate tags");
     628               0 :                 PushIntoMisplacedStack(current);
     629                 :               }
     630                 : 
     631                 :               // XXX Add code to also collect incorrect attributes on the
     632                 :               // end tag.
     633                 :             }
     634                 : 
     635              54 :             if (DoesRequireBody(aToken, mTokenizer)) {
     636                 :               CToken* theBodyToken =
     637                 :                 mTokenAllocator->CreateTokenOfType(eToken_start,
     638                 :                                                    eHTMLTag_body,
     639              25 :                                                    NS_LITERAL_STRING("body"));
     640              25 :               result = HandleToken(theBodyToken);
     641                 :             }
     642              54 :             return result;
     643                 :           }
     644                 :         }
     645                 :       }
     646                 :   }
     647                 : 
     648            2361 :   if (theToken) {
     649            2361 :     switch (theType) {
     650                 :       case eToken_text:
     651                 :       case eToken_start:
     652                 :       case eToken_whitespace:
     653                 :       case eToken_newline:
     654            1967 :         result = HandleStartToken(theToken);
     655            1967 :         break;
     656                 : 
     657                 :       case eToken_end:
     658             344 :         result = HandleEndToken(theToken);
     659             344 :         break;
     660                 : 
     661                 :       case eToken_cdatasection:
     662                 :       case eToken_comment:
     663                 :       case eToken_markupDecl:
     664              25 :         result = HandleCommentToken(theToken);
     665              25 :         break;
     666                 : 
     667                 :       case eToken_entity:
     668               0 :         result = HandleEntityToken(theToken);
     669               0 :         break;
     670                 : 
     671                 :       case eToken_attribute:
     672               0 :         result = HandleAttributeToken(theToken);
     673               0 :         break;
     674                 : 
     675                 :       case eToken_instruction:
     676               0 :         result = HandleProcessingInstructionToken(theToken);
     677               0 :         break;
     678                 : 
     679                 :       case eToken_doctypeDecl:
     680              25 :         result = HandleDocTypeDeclToken(theToken);
     681              25 :         break;
     682                 : 
     683                 :       default:
     684               0 :         break;
     685                 :     }
     686                 : 
     687            2361 :     IF_FREE(theToken, mTokenAllocator);
     688            2361 :     if (result == NS_ERROR_HTMLPARSER_STOPPARSING) {
     689               0 :       mFlags |= NS_DTD_FLAG_STOP_PARSING;
     690            2361 :     } else if (NS_FAILED(result) && result != NS_ERROR_HTMLPARSER_BLOCK) {
     691               0 :       result = NS_OK;
     692                 :     }
     693                 :   }
     694                 : 
     695            2361 :   return result;
     696                 : }
     697                 : 
     698                 : nsresult
     699            1967 : CNavDTD::DidHandleStartTag(nsIParserNode& aNode, eHTMLTags aChildTag)
     700                 : {
     701            1967 :   nsresult result = NS_OK;
     702                 : 
     703            1967 :   switch (aChildTag) {
     704                 :     case eHTMLTag_pre:
     705                 :     case eHTMLTag_listing:
     706                 :       {
     707                 :         // Skip the 1st newline inside PRE and LISTING unless this is a
     708                 :         // plain text doc (for which we pushed a PRE in CNavDTD::BuildModel).
     709                 : 
     710                 :         // XXX This code is incorrect in the face of misplaced <pre> and
     711                 :         // <listing> tags (as direct children of <table>).
     712               0 :         CToken* theNextToken = mTokenizer->PeekToken();
     713               0 :         if (ePlainText != mDocType && theNextToken) {
     714               0 :           eHTMLTokenTypes theType = eHTMLTokenTypes(theNextToken->GetTokenType());
     715               0 :           if (eToken_newline == theType) {
     716               0 :             if (mCountLines) {
     717               0 :               mLineNumber += theNextToken->GetNewlineCount();
     718                 :             }
     719               0 :             theNextToken = mTokenizer->PopToken();
     720               0 :             IF_FREE(theNextToken, mTokenAllocator); // fix for Bug 29379
     721                 :           }
     722                 :         }
     723                 :       }
     724               0 :       break;
     725                 : 
     726                 :     default:
     727            1967 :       break;
     728                 :   }
     729                 : 
     730            1967 :   return result;
     731                 : }
     732                 : 
     733                 : PRInt32
     734               0 : CNavDTD::LastOf(eHTMLTags aTagSet[], PRInt32 aCount) const
     735                 : {
     736               0 :   for (PRInt32 theIndex = mBodyContext->GetCount() - 1; theIndex >= 0;
     737                 :        --theIndex) {
     738               0 :     if (FindTagInSet((*mBodyContext)[theIndex], aTagSet, aCount)) {
     739               0 :       return theIndex;
     740                 :     }
     741                 :   }
     742                 : 
     743               0 :   return kNotFound;
     744                 : }
     745                 : 
     746                 : static bool
     747              62 : CanBeContained(eHTMLTags aChildTag, nsDTDContext& aContext)
     748                 : {
     749                 :   /* #    Interesting test cases:       Result:
     750                 :    * 1.   <UL><LI>..<B>..<LI>           inner <LI> closes outer <LI>
     751                 :    * 2.   <CENTER><DL><DT><A><CENTER>   allow nested <CENTER>
     752                 :    * 3.   <TABLE><TR><TD><TABLE>...     allow nested <TABLE>
     753                 :    * 4.   <FRAMESET> ... <FRAMESET>
     754                 :    */
     755              62 :   bool    result = true;
     756              62 :   PRInt32 theCount = aContext.GetCount();
     757                 : 
     758              62 :   if (0 < theCount) {
     759              62 :     const TagList* theRootTags = gHTMLElements[aChildTag].GetRootTags();
     760                 :     const TagList* theSpecialParents =
     761              62 :       gHTMLElements[aChildTag].GetSpecialParents();
     762                 : 
     763              62 :     if (theRootTags) {
     764              62 :       PRInt32 theRootIndex = LastOf(aContext, *theRootTags);
     765                 :       PRInt32 theSPIndex = theSpecialParents
     766                 :                            ? LastOf(aContext, *theSpecialParents)
     767              62 :                            : kNotFound;
     768                 :       PRInt32 theChildIndex =
     769              62 :         nsHTMLElement::GetIndexOfChildOrSynonym(aContext, aChildTag);
     770                 :       PRInt32 theTargetIndex = (theRootIndex > theSPIndex)
     771                 :                                ? theRootIndex
     772              62 :                                : theSPIndex;
     773                 : 
     774              62 :       if (theTargetIndex == theCount-1 ||
     775                 :           (theTargetIndex == theChildIndex &&
     776               0 :            gHTMLElements[aChildTag].CanContainSelf())) {
     777              62 :         result = true;
     778                 :       } else {
     779               0 :         result = false;
     780                 : 
     781                 :         static eHTMLTags gTableElements[] = { eHTMLTag_td, eHTMLTag_th };
     782                 : 
     783               0 :         PRInt32 theIndex = theCount - 1;
     784               0 :         while (theChildIndex < theIndex) {
     785               0 :           eHTMLTags theParentTag = aContext.TagAt(theIndex--);
     786               0 :           if (gHTMLElements[theParentTag].IsMemberOf(kBlockEntity)  ||
     787               0 :               gHTMLElements[theParentTag].IsMemberOf(kHeading)      ||
     788               0 :               gHTMLElements[theParentTag].IsMemberOf(kPreformatted) ||
     789               0 :               gHTMLElements[theParentTag].IsMemberOf(kFormControl)  ||  //fixes bug 44479
     790               0 :               gHTMLElements[theParentTag].IsMemberOf(kList)) {
     791               0 :             if (!HasOptionalEndTag(theParentTag)) {
     792               0 :               result = true;
     793               0 :               break;
     794                 :             }
     795               0 :           } else if (FindTagInSet(theParentTag, gTableElements,
     796               0 :                                   ArrayLength(gTableElements))) {
     797                 :             // Added this to catch a case we missed; bug 57173.
     798               0 :             result = true;
     799               0 :             break;
     800                 :           }
     801                 :         }
     802                 :       }
     803                 :     }
     804                 :   }
     805                 : 
     806              62 :   return result;
     807                 : }
     808                 : 
     809                 : enum eProcessRule { eNormalOp, eLetInlineContainBlock };
     810                 : 
     811                 : nsresult
     812            1817 : CNavDTD::HandleDefaultStartToken(CToken* aToken, eHTMLTags aChildTag,
     813                 :                                  nsCParserNode *aNode)
     814                 : {
     815            1817 :   NS_PRECONDITION(nsnull != aToken, kNullToken);
     816                 : 
     817            1817 :   nsresult  result = NS_OK;
     818            1817 :   bool    theChildIsContainer = nsHTMLElement::IsContainer(aChildTag);
     819                 : 
     820                 :   // Client of parser is spefically trying to parse a fragment that
     821                 :   // may lack required context.  Suspend containment rules if so.
     822            1817 :   if (mParserCommand != eViewFragment) {
     823            1817 :     bool    theChildAgrees = true;
     824            1817 :     PRInt32 theIndex = mBodyContext->GetCount();
     825            1817 :     PRInt32 theParentContains = 0;
     826                 : 
     827            2477 :     do {
     828            2147 :       eHTMLTags theParentTag = mBodyContext->TagAt(--theIndex);
     829            2147 :       if (theParentTag == eHTMLTag_userdefined) {
     830               0 :         continue;
     831                 :       }
     832                 : 
     833                 :       // Figure out whether this is a hidden input inside a
     834                 :       // table/tbody/thead/tfoot/tr
     835                 :       static eHTMLTags sTableElements[] = {
     836                 :         eHTMLTag_table, eHTMLTag_thead, eHTMLTag_tbody,
     837                 :         eHTMLTag_tr, eHTMLTag_tfoot
     838                 :       };
     839                 : 
     840            2147 :       bool isHiddenInputInsideTableElement = false;
     841            2147 :       if (aChildTag == eHTMLTag_input &&
     842                 :           FindTagInSet(theParentTag, sTableElements,
     843               0 :                        ArrayLength(sTableElements))) {
     844               0 :         PRInt32 attrCount = aNode->GetAttributeCount();
     845               0 :         for (PRInt32 attrIndex = 0; attrIndex < attrCount; ++attrIndex) {
     846               0 :           const nsAString& key = aNode->GetKeyAt(attrIndex);
     847               0 :           if (key.LowerCaseEqualsLiteral("type")) {
     848                 :             isHiddenInputInsideTableElement =
     849               0 :               ValueIsHidden(aNode->GetValueAt(attrIndex));
     850               0 :             break;
     851                 :           }
     852                 :         }
     853                 :       }
     854                 :       
     855                 :       // Precompute containment, and pass it to CanOmit()...
     856                 :       theParentContains =
     857            2147 :         isHiddenInputInsideTableElement || CanContain(theParentTag, aChildTag);
     858            4294 :       if (!isHiddenInputInsideTableElement &&
     859            2147 :           CanOmit(theParentTag, aChildTag, theParentContains)) {
     860               0 :         HandleOmittedTag(aToken, aChildTag, theParentTag, aNode);
     861               0 :         return NS_OK;
     862                 :       }
     863                 : 
     864            2147 :       eProcessRule theRule = eNormalOp;
     865                 : 
     866            2538 :       if (!theParentContains &&
     867             330 :           (IsBlockElement(aChildTag, theParentTag) &&
     868              61 :            IsInlineElement(theParentTag, theParentTag))) {
     869                 :         // Don't test for table to fix 57554.
     870              61 :         if (eHTMLTag_li != aChildTag) {
     871              61 :           nsCParserNode* theParentNode = mBodyContext->PeekNode();
     872              61 :           if (theParentNode && theParentNode->mToken->IsWellFormed()) {
     873               0 :             theRule = eLetInlineContainBlock;
     874                 :           }
     875                 :         }
     876                 :       }
     877                 : 
     878            2147 :       switch (theRule) {
     879                 :         case eNormalOp:
     880            2147 :           theChildAgrees = true;
     881            2147 :           if (theParentContains) {
     882            1817 :             eHTMLTags theAncestor = gHTMLElements[aChildTag].mRequiredAncestor;
     883            1817 :             if (eHTMLTag_unknown != theAncestor) {
     884               0 :               theChildAgrees = HasOpenContainer(theAncestor);
     885                 :             }
     886                 : 
     887            1817 :             if (theChildAgrees && theChildIsContainer) {
     888             800 :               if (theParentTag != aChildTag) {
     889                 :                 // Double check the power structure
     890                 :                 // Note: The bit is currently set on tags such as <A> and <LI>.
     891             772 :                 if (gHTMLElements[aChildTag].ShouldVerifyHierarchy()) {
     892                 :                   PRInt32 theChildIndex =
     893                 :                     nsHTMLElement::GetIndexOfChildOrSynonym(*mBodyContext,
     894             490 :                                                             aChildTag);
     895                 : 
     896             490 :                   if (kNotFound < theChildIndex && theChildIndex < theIndex) {
     897                 :                     /*
     898                 :                      * 1  Here's a tricky case from bug 22596:  <h5><li><h5>
     899                 :                      *    How do we know that the 2nd <h5> should close the <LI>
     900                 :                      *    rather than nest inside the <LI>? (Afterall, the <h5>
     901                 :                      *    is a legal child of the <LI>).
     902                 :                      *
     903                 :                      *    The way you know is that there is no root between the
     904                 :                      *    two, so the <h5> binds more tightly to the 1st <h5>
     905                 :                      *    than to the <LI>.
     906                 :                      *
     907                 :                      * 2  Also, bug 6148 shows this case: <SPAN><DIV><SPAN>
     908                 :                      *    From this case we learned not to execute this logic if
     909                 :                      *    the parent is a block.
     910                 :                      *
     911                 :                      * 3  Fix for 26583:
     912                 :                      *    <A href=foo.html><B>foo<A href-bar.html>bar</A></B></A>
     913                 :                      *    In the above example clicking on "foo" or "bar" should
     914                 :                      *    link to foo.html or bar.html respectively. That is,
     915                 :                      *    the inner <A> should be informed about the presence of
     916                 :                      *    an open <A> above <B>..so that the inner <A> can close
     917                 :                      *    out the outer <A>. The following code does it for us.
     918                 :                      *
     919                 :                      * 4  Fix for 27865 [ similer to 22596 ]. Ex:
     920                 :                      *    <DL><DD><LI>one<DD><LI>two
     921                 :                      */
     922              62 :                     theChildAgrees = CanBeContained(aChildTag, *mBodyContext);
     923                 :                   }
     924                 :                 }
     925                 :               }
     926                 :             }
     927                 :           }
     928                 : 
     929            2147 :           if (!(theParentContains && theChildAgrees)) {
     930             330 :             if (!CanPropagate(theParentTag, aChildTag, theParentContains)) {
     931             330 :               if (theChildIsContainer || !theParentContains) {
     932             330 :                 if (!theChildAgrees &&
     933               0 :                     !gHTMLElements[aChildTag].CanAutoCloseTag(*mBodyContext,
     934                 :                                                               theIndex,
     935               0 :                                                               aChildTag)) {
     936                 :                   // Closing the tags above might cause non-compatible results.
     937                 :                   // Ex. <TABLE><TR><TD><TBODY>Text</TD></TR></TABLE>.
     938                 :                   // In the example above <TBODY> is badly misplaced, but
     939                 :                   // we should not attempt to close the tags above it,
     940                 :                   // The safest thing to do is to discard this tag.
     941                 :                   // XXX We get the above example wrong anyway because of
     942                 :                   // CanBeContained.
     943               0 :                   return result;
     944             330 :                 } else if (mBodyContext->mContextTopIndex > 0 &&
     945                 :                            theIndex <= mBodyContext->mContextTopIndex) {
     946                 :                   // Looks like the parent tag does not want to contain the
     947                 :                   // current tag ( aChildTag ).  However, we have to force the
     948                 :                   // containment, when handling misplaced content, to avoid data
     949                 :                   // loss.  Ref. bug 138577.
     950               0 :                   theParentContains = true;
     951                 :                 } else {
     952             330 :                   CloseContainersTo(theIndex, aChildTag, true);
     953                 :                 }
     954                 :               } else {
     955               0 :                 break;
     956                 :               }
     957                 :             } else {
     958               0 :               CreateContextStackFor(theParentTag, aChildTag);
     959               0 :               theIndex = mBodyContext->GetCount();
     960                 :             }
     961                 :           }
     962            2147 :           break;
     963                 : 
     964                 :         case eLetInlineContainBlock:
     965                 :           // Break out of this loop and open the block.
     966               0 :           theParentContains = theChildAgrees = true;
     967               0 :           break;
     968                 : 
     969                 :         default:
     970               0 :           NS_NOTREACHED("Invalid rule detected");
     971                 :       }
     972            3964 :     } while (!(theParentContains && theChildAgrees));
     973                 :   }
     974                 : 
     975            1817 :   if (theChildIsContainer) {
     976             800 :     result = OpenContainer(aNode, aChildTag);
     977                 :   } else {
     978            1017 :     result = AddLeaf(aNode);
     979                 :   }
     980                 : 
     981            1817 :   return result;
     982                 : }
     983                 : 
     984                 : nsresult
     985            1967 : CNavDTD::WillHandleStartTag(CToken* aToken, eHTMLTags aTag,
     986                 :                             nsIParserNode& aNode)
     987                 : {
     988            1967 :   nsresult result = NS_OK;
     989                 : 
     990            1967 :   PRInt32 stackDepth = mBodyContext->GetCount();
     991            1967 :   if (stackDepth >= FONTSTYLE_IGNORE_DEPTH &&
     992               0 :       gHTMLElements[aTag].IsMemberOf(kFontStyle)) {
     993                 :     // Prevent bug 58917 by tossing the new kFontStyle start tag
     994               0 :     return kHierarchyTooDeep;
     995                 :   }
     996                 : 
     997            1967 :   if (stackDepth >= PHRASE_IGNORE_DEPTH &&
     998               0 :       gHTMLElements[aTag].IsMemberOf(kPhrase)) {
     999                 :     // Prevent bug 58917 by tossing the new kPhrase start tag
    1000               0 :     return kHierarchyTooDeep;
    1001                 :   }
    1002                 : 
    1003                 :   /*
    1004                 :    * Now a little code to deal with bug #49687 (crash when layout stack gets
    1005                 :    * too deep) I've also opened this up to any container (not just inlines):
    1006                 :    * re bug 55095 Improved to handle bug 55980 (infinite loop caused when
    1007                 :    * DEPTH is exceeded and </P> is encountered by itself (<P>) is continuously
    1008                 :    * produced.
    1009                 :    */
    1010            1967 :   if (stackDepth > MAX_REFLOW_DEPTH) {
    1011               0 :     if (nsHTMLElement::IsContainer(aTag) &&
    1012               0 :         !gHTMLElements[aTag].HasSpecialProperty(kHandleStrayTag)) {
    1013                 :       // Ref. bug 98261,49678,55095,55980
    1014                 :       // Instead of throwing away the current tag close it's parent
    1015                 :       // such that the stack level does not go beyond the max_reflow_depth.
    1016                 :       // This would allow leaf tags, that follow the current tag, to find
    1017                 :       // the correct node.
    1018               0 :       while (stackDepth != MAX_REFLOW_DEPTH && NS_SUCCEEDED(result)) {
    1019               0 :         result = CloseContainersTo(mBodyContext->Last(), false);
    1020               0 :         --stackDepth;
    1021                 :       }
    1022                 :     }
    1023                 :   }
    1024                 : 
    1025            1967 :   return result;
    1026                 : }
    1027                 : 
    1028                 : static void
    1029               0 : PushMisplacedAttributes(nsIParserNode& aNode, nsDeque& aDeque)
    1030                 : {
    1031               0 :   nsCParserNode& theAttrNode = static_cast<nsCParserNode &>(aNode);
    1032                 : 
    1033               0 :   for (PRInt32 count = aNode.GetAttributeCount(); count > 0; --count) {
    1034               0 :     CToken* theAttrToken = theAttrNode.PopAttributeTokenFront();
    1035               0 :     if (theAttrToken) {
    1036               0 :       theAttrToken->SetNewlineCount(0);
    1037               0 :       aDeque.Push(theAttrToken);
    1038                 :     }
    1039                 :   }
    1040               0 : }
    1041                 : 
    1042                 : void
    1043               0 : CNavDTD::HandleOmittedTag(CToken* aToken, eHTMLTags aChildTag,
    1044                 :                           eHTMLTags aParent, nsIParserNode* aNode)
    1045                 : {
    1046               0 :   NS_PRECONDITION(mBodyContext != nsnull, "need a context to work with");
    1047                 : 
    1048                 :   // The trick here is to see if the parent can contain the child, but prefers
    1049                 :   // not to. Only if the parent CANNOT contain the child should we look to see
    1050                 :   // if it's potentially a child of another section. If it is, the cache it for
    1051                 :   // later.
    1052               0 :   PRInt32 theTagCount = mBodyContext->GetCount();
    1053               0 :   bool pushToken = false;
    1054                 : 
    1055               0 :   if (gHTMLElements[aParent].HasSpecialProperty(kBadContentWatch) &&
    1056               0 :       !nsHTMLElement::IsWhitespaceTag(aChildTag)) {
    1057               0 :     eHTMLTags theTag = eHTMLTag_unknown;
    1058                 : 
    1059                 :     // Don't bother saving misplaced stuff in the head. This can happen in
    1060                 :     // cases like |<head><noscript><table>foo|. See bug 401169.
    1061               0 :     if (mFlags & NS_DTD_FLAG_HAS_OPEN_HEAD) {
    1062               0 :       NS_ASSERTION(!(mFlags & NS_DTD_FLAG_HAS_MAIN_CONTAINER),
    1063                 :                    "Bad state");
    1064               0 :       return;
    1065                 :     }
    1066                 : 
    1067                 :     // Determine the insertion point
    1068               0 :     while (theTagCount > 0) {
    1069               0 :       theTag = mBodyContext->TagAt(--theTagCount);
    1070               0 :       if (!gHTMLElements[theTag].HasSpecialProperty(kBadContentWatch)) {
    1071                 :         // This is our insertion point.
    1072               0 :         mBodyContext->mContextTopIndex = theTagCount;
    1073               0 :         break;
    1074                 :       }
    1075                 :     }
    1076                 : 
    1077               0 :     if (mBodyContext->mContextTopIndex > -1) {
    1078               0 :       pushToken = true;
    1079                 : 
    1080                 :       // Remember that we've stashed some misplaced content.
    1081               0 :       mFlags |= NS_DTD_FLAG_MISPLACED_CONTENT;
    1082                 :     }
    1083                 :   }
    1084                 : 
    1085               0 :   if (aChildTag != aParent &&
    1086               0 :       gHTMLElements[aParent].HasSpecialProperty(kSaveMisplaced)) {
    1087               0 :     NS_ASSERTION(!pushToken, "A strange element has both kBadContentWatch "
    1088                 :                              "and kSaveMisplaced");
    1089               0 :     pushToken = true;
    1090                 :   }
    1091                 : 
    1092               0 :   if (pushToken) {
    1093                 :     // Hold on to this token for later use. Ref Bug. 53695
    1094               0 :     IF_HOLD(aToken);
    1095               0 :     PushIntoMisplacedStack(aToken);
    1096                 : 
    1097                 :     // If the token is attributed then save those attributes too.
    1098               0 :     PushMisplacedAttributes(*aNode, mMisplacedContent);
    1099                 :   }
    1100                 : }
    1101                 : 
    1102                 : /**
    1103                 :  *  This method gets called when a kegen token is found.
    1104                 :  *   
    1105                 :  *  @update  harishd 05/02/00
    1106                 :  *  @param   aNode -- CParserNode representing keygen
    1107                 :  *  @return  NS_OK if all went well; ERROR if error occurred
    1108                 :  */
    1109                 : nsresult
    1110               0 : CNavDTD::HandleKeyGen(nsIParserNode* aNode)
    1111                 : {
    1112               0 :   nsresult result = NS_OK;
    1113                 : 
    1114                 :   nsCOMPtr<nsIFormProcessor> theFormProcessor =
    1115               0 :            do_GetService(kFormProcessorCID, &result);
    1116               0 :   if (NS_FAILED(result)) {
    1117               0 :     return result;
    1118                 :   }
    1119                 : 
    1120               0 :   PRInt32      theAttrCount = aNode->GetAttributeCount();
    1121               0 :   nsTArray<nsString> theContent;
    1122               0 :   nsAutoString theAttribute;
    1123               0 :   nsAutoString theFormType;
    1124               0 :   CToken*      theToken = nsnull;
    1125                 : 
    1126               0 :   theFormType.AssignLiteral("select");
    1127                 : 
    1128               0 :   result = theFormProcessor->ProvideContent(theFormType, theContent,
    1129               0 :                                             theAttribute);
    1130               0 :   if (NS_FAILED(result)) {
    1131               0 :     return result;
    1132                 :   }
    1133               0 :   PRInt32   theIndex = nsnull;
    1134                 : 
    1135                 :   // Populate the tokenizer with the fabricated elements in the reverse
    1136                 :   // order such that <SELECT> is on the top fo the tokenizer followed by
    1137                 :   // <OPTION>s and </SELECT>.
    1138                 :   theToken = mTokenAllocator->CreateTokenOfType(eToken_end,
    1139               0 :                                                 eHTMLTag_select);
    1140               0 :   NS_ENSURE_TRUE(theToken, NS_ERROR_OUT_OF_MEMORY);
    1141               0 :   mTokenizer->PushTokenFront(theToken);
    1142                 : 
    1143               0 :   for (theIndex = theContent.Length()-1; theIndex > -1; --theIndex) {
    1144                 :     theToken = mTokenAllocator->CreateTokenOfType(eToken_text,
    1145                 :                                                   eHTMLTag_text,
    1146               0 :                                                   theContent[theIndex]);
    1147               0 :     NS_ENSURE_TRUE(theToken, NS_ERROR_OUT_OF_MEMORY);
    1148               0 :     mTokenizer->PushTokenFront(theToken);
    1149                 : 
    1150                 :     theToken = mTokenAllocator->CreateTokenOfType(eToken_start,
    1151               0 :                                                   eHTMLTag_option);
    1152               0 :     NS_ENSURE_TRUE(theToken, NS_ERROR_OUT_OF_MEMORY);
    1153               0 :     mTokenizer->PushTokenFront(theToken);
    1154                 :   }
    1155                 : 
    1156                 :   // The attribute ( provided by the form processor ) should be a part
    1157                 :   // of the SELECT.  Placing the attribute token on the tokenizer to get
    1158                 :   // picked up by the SELECT.
    1159                 :   theToken = mTokenAllocator->CreateTokenOfType(eToken_attribute,
    1160                 :                                                 eHTMLTag_unknown,
    1161               0 :                                                 theAttribute);
    1162               0 :   NS_ENSURE_TRUE(theToken, NS_ERROR_OUT_OF_MEMORY);
    1163                 : 
    1164               0 :   ((CAttributeToken*)theToken)->SetKey(NS_LITERAL_STRING("_moz-type"));
    1165               0 :   mTokenizer->PushTokenFront(theToken);
    1166                 : 
    1167                 :   // Pop out NAME and CHALLENGE attributes ( from the keygen NODE ) and
    1168                 :   // place it in the tokenizer such that the attribtues get sucked into
    1169                 :   // SELECT node.
    1170               0 :   for (theIndex = theAttrCount; theIndex > 0; --theIndex) {
    1171               0 :     mTokenizer->PushTokenFront(((nsCParserNode*)aNode)->PopAttributeToken());
    1172                 :   }
    1173                 : 
    1174                 :   theToken = mTokenAllocator->CreateTokenOfType(eToken_start,
    1175               0 :                                                 eHTMLTag_select);
    1176               0 :   NS_ENSURE_TRUE(theToken, NS_ERROR_OUT_OF_MEMORY);
    1177                 : 
    1178                 :   // Increment the count because of the additional attribute from the form processor.
    1179               0 :   theToken->SetAttributeCount(theAttrCount + 1);
    1180               0 :   mTokenizer->PushTokenFront(theToken);
    1181                 : 
    1182               0 :   return result;
    1183                 : }
    1184                 : 
    1185                 : bool
    1186              54 : CNavDTD::IsAlternateTag(eHTMLTags aTag)
    1187                 : {
    1188              54 :   switch (aTag) {
    1189                 :     case eHTMLTag_noembed:
    1190               0 :       return true;
    1191                 : 
    1192                 :     case eHTMLTag_noscript:
    1193               0 :       return (mFlags & NS_IPARSER_FLAG_SCRIPT_ENABLED) != 0;
    1194                 : 
    1195                 :     case eHTMLTag_iframe:
    1196                 :     case eHTMLTag_noframes:
    1197               0 :       return (mFlags & NS_IPARSER_FLAG_FRAMES_ENABLED) != 0;
    1198                 : 
    1199                 :     default:
    1200              54 :       return false;
    1201                 :   }
    1202                 : }
    1203                 : 
    1204                 : nsresult
    1205            1967 : CNavDTD::HandleStartToken(CToken* aToken)
    1206                 : {
    1207            1967 :   NS_PRECONDITION(nsnull != aToken, kNullToken);
    1208                 : 
    1209            1967 :   nsCParserNode* theNode = mNodeAllocator.CreateNode(aToken, mTokenAllocator);
    1210            1967 :   NS_ENSURE_TRUE(theNode, NS_ERROR_OUT_OF_MEMORY);
    1211                 : 
    1212            1967 :   eHTMLTags     theChildTag = (eHTMLTags)aToken->GetTypeID();
    1213            1967 :   PRInt16       attrCount   = aToken->GetAttributeCount();
    1214            1967 :   eHTMLTags     theParent   = mBodyContext->Last();
    1215            1967 :   nsresult      result      = NS_OK;
    1216                 : 
    1217            1967 :   if (attrCount > 0) {
    1218             237 :     result = CollectAttributes(theNode, theChildTag, attrCount);
    1219                 :   }
    1220                 : 
    1221            1967 :   if (NS_OK == result) {
    1222            1967 :     result = WillHandleStartTag(aToken, theChildTag, *theNode);
    1223            1967 :     if (NS_OK == result) {
    1224            1967 :       bool isTokenHandled = false;
    1225            1967 :       bool theHeadIsParent = false;
    1226                 : 
    1227            1967 :       if (nsHTMLElement::IsSectionTag(theChildTag)) {
    1228              56 :         switch (theChildTag) {
    1229                 :           case eHTMLTag_html:
    1230              28 :             if (mBodyContext->GetCount() > 0) {
    1231               0 :               result = OpenContainer(theNode, theChildTag);
    1232               0 :               isTokenHandled = true;
    1233                 :             }
    1234              28 :             break;
    1235                 : 
    1236                 :           case eHTMLTag_body:
    1237              28 :             if (mFlags & NS_DTD_FLAG_HAS_OPEN_BODY) {
    1238               0 :               result = OpenContainer(theNode, theChildTag);
    1239               0 :               isTokenHandled=true;
    1240                 :             }
    1241              28 :             break;
    1242                 : 
    1243                 :           case eHTMLTag_head:
    1244               0 :             mFlags |= NS_DTD_FLAG_HAS_EXPLICIT_HEAD;
    1245                 : 
    1246               0 :             if (mFlags & NS_DTD_FLAG_HAS_MAIN_CONTAINER) {
    1247               0 :               HandleOmittedTag(aToken, theChildTag, theParent, theNode);
    1248               0 :               isTokenHandled = true;
    1249                 :             }
    1250               0 :             break;
    1251                 : 
    1252                 :           default:
    1253               0 :             break;
    1254                 :         }
    1255                 :       }
    1256                 : 
    1257            1967 :       bool isExclusive = false;
    1258            1967 :       theHeadIsParent = nsHTMLElement::IsChildOfHead(theChildTag, isExclusive);
    1259                 : 
    1260            1967 :       switch (theChildTag) {
    1261                 :         case eHTMLTag_area:
    1262               0 :           if (!mOpenMapCount) {
    1263               0 :             isTokenHandled = true;
    1264                 :           }
    1265                 : 
    1266               0 :           if (mOpenMapCount > 0 && mSink) {
    1267               0 :             result = mSink->AddLeaf(*theNode);
    1268               0 :             isTokenHandled = true;
    1269                 :           }
    1270                 :           
    1271               0 :           break;
    1272                 : 
    1273                 :         case eHTMLTag_image:
    1274               0 :           aToken->SetTypeID(theChildTag = eHTMLTag_img);
    1275               0 :           break;
    1276                 : 
    1277                 :         case eHTMLTag_keygen:
    1278               0 :           result = HandleKeyGen(theNode);
    1279               0 :           isTokenHandled = true;
    1280               0 :           break;
    1281                 : 
    1282                 :         case eHTMLTag_script:
    1283                 :           // Script isn't really exclusively in the head. However, we treat it
    1284                 :           // as such to make sure that we don't pull scripts outside the head
    1285                 :           // into the body.
    1286                 :           // XXX Where does the script go in a frameset document?
    1287               0 :           isExclusive = !(mFlags & NS_DTD_FLAG_HAD_BODY);
    1288               0 :           break;
    1289                 : 
    1290                 :         default:;
    1291                 :       }
    1292                 : 
    1293            1967 :       if (!isTokenHandled) {
    1294                 :         bool prefersBody =
    1295            1967 :           gHTMLElements[theChildTag].HasSpecialProperty(kPreferBody);
    1296                 : 
    1297                 :         // If this tag prefers to be in the head (when neither the head nor the
    1298                 :         // body have been explicitly opened) then check that we haven't seen the
    1299                 :         // body (true until the <body> tag has really been seen). Otherwise,
    1300                 :         // check if the head has been explicitly opened. See bug 307122.
    1301                 :         theHeadIsParent = theHeadIsParent &&
    1302                 :           (isExclusive ||
    1303                 :            (prefersBody
    1304                 :             ? (mFlags & NS_DTD_FLAG_HAS_EXPLICIT_HEAD) &&
    1305                 :               (mFlags & NS_DTD_FLAG_HAS_OPEN_HEAD)
    1306            1967 :             : !(mFlags & NS_DTD_FLAG_HAS_MAIN_CONTAINER)));
    1307                 : 
    1308            1967 :         if (theHeadIsParent) {
    1309                 :           // These tokens prefer to be in the head.
    1310             150 :           result = AddHeadContent(theNode);
    1311                 :         } else {
    1312            1817 :           result = HandleDefaultStartToken(aToken, theChildTag, theNode);
    1313                 :         }
    1314                 :       }
    1315                 : 
    1316                 :       // Now do any post processing necessary on the tag...
    1317            1967 :       if (NS_OK == result) {
    1318            1967 :         DidHandleStartTag(*theNode, theChildTag);
    1319                 :       }
    1320                 :     }
    1321                 :   }
    1322                 : 
    1323            1967 :   if (kHierarchyTooDeep == result) {
    1324                 :     // Reset this error to ok; all that happens here is that given inline tag
    1325                 :     // gets dropped because the stack is too deep. Don't terminate parsing.
    1326               0 :     result = NS_OK;
    1327                 :   }
    1328                 : 
    1329            1967 :   IF_FREE(theNode, &mNodeAllocator);
    1330            1967 :   return result;
    1331                 : }
    1332                 : 
    1333                 : /**
    1334                 :  *  Call this to see if you have a closeable peer on the stack that
    1335                 :  *  is ABOVE one of its root tags.
    1336                 :  *
    1337                 :  *  @update  gess 4/11/99
    1338                 :  *  @param   aRootTagList -- list of root tags for aTag
    1339                 :  *  @param   aTag -- tag to test for containership
    1340                 :  *  @return  true if given tag can contain other tags
    1341                 :  */
    1342                 : static bool
    1343              86 : HasCloseablePeerAboveRoot(const TagList& aRootTagList, nsDTDContext& aContext,
    1344                 :                           eHTMLTags aTag, bool anEndTag)
    1345                 : {
    1346              86 :   PRInt32  theRootIndex = LastOf(aContext, aRootTagList);
    1347                 :   const TagList* theCloseTags = anEndTag
    1348              86 :                                 ? gHTMLElements[aTag].GetAutoCloseEndTags()
    1349             172 :                                 : gHTMLElements[aTag].GetAutoCloseStartTags();
    1350              86 :   PRInt32 theChildIndex = -1;
    1351                 : 
    1352              86 :   if (theCloseTags) {
    1353               0 :     theChildIndex=LastOf(aContext, *theCloseTags);
    1354              86 :   } else if (anEndTag || !gHTMLElements[aTag].CanContainSelf()) {
    1355              86 :     theChildIndex = aContext.LastOf(aTag);
    1356                 :   }
    1357                 : 
    1358                 :   // I changed this to theRootIndex<=theChildIndex so to handle this case:
    1359                 :   //  <SELECT><OPTGROUP>...</OPTGROUP>
    1360              86 :   return theRootIndex<=theChildIndex;
    1361                 : }
    1362                 : 
    1363                 : 
    1364                 : /**
    1365                 :  *  This method is called to determine whether or not an END tag
    1366                 :  *  can be autoclosed. This means that based on the current
    1367                 :  *  context, the stack should be closed to the nearest matching
    1368                 :  *  tag.
    1369                 :  *
    1370                 :  *  @param   aTag -- tag enum of child to be tested
    1371                 :  *  @return  true if autoclosure should occur
    1372                 :  */
    1373                 : static eHTMLTags
    1374             344 : FindAutoCloseTargetForEndTag(eHTMLTags aCurrentTag, nsDTDContext& aContext,
    1375                 :                              nsDTDMode aMode)
    1376                 : {
    1377             344 :   int theTopIndex = aContext.GetCount();
    1378             344 :   eHTMLTags thePrevTag = aContext.Last();
    1379                 : 
    1380             344 :   if (nsHTMLElement::IsContainer(aCurrentTag)) {
    1381                 :     PRInt32 theChildIndex =
    1382             344 :       nsHTMLElement::GetIndexOfChildOrSynonym(aContext, aCurrentTag);
    1383                 : 
    1384             344 :     if (kNotFound < theChildIndex) {
    1385             344 :       if (thePrevTag == aContext[theChildIndex]) {
    1386             258 :         return aContext[theChildIndex];
    1387                 :       }
    1388                 : 
    1389              86 :       if (nsHTMLElement::IsBlockCloser(aCurrentTag)) {
    1390                 :         /*
    1391                 :          * Here's the algorithm:
    1392                 :          * Our here is sitting at aChildIndex. There are other tags above it
    1393                 :          * on the stack. We have to try to close them out, but we may encounter
    1394                 :          * one that can block us. The way to tell is by comparing each tag on
    1395                 :          * the stack against our closeTag and rootTag list.
    1396                 :          *
    1397                 :          * For each tag above our hero on the stack, ask 3 questions:
    1398                 :          * 1. Is it in the closeTag list? If so, the we can skip over it
    1399                 :          * 2. Is it in the rootTag list? If so, then we're gated by it
    1400                 :          * 3. Otherwise its non-specified and we simply presume we can close it.
    1401                 :          */
    1402                 :         const TagList* theCloseTags =
    1403              86 :           gHTMLElements[aCurrentTag].GetAutoCloseEndTags();
    1404                 :         const TagList* theRootTags =
    1405              86 :           gHTMLElements[aCurrentTag].GetEndRootTags();
    1406                 : 
    1407              86 :         if (theCloseTags) {
    1408                 :           // At a mininimum, this code is needed for H1..H6
    1409               0 :           while (theChildIndex < --theTopIndex) {
    1410               0 :             eHTMLTags theNextTag = aContext[theTopIndex];
    1411               0 :             if (!FindTagInSet(theNextTag, theCloseTags->mTags,
    1412               0 :                               theCloseTags->mCount) &&
    1413                 :                 FindTagInSet(theNextTag, theRootTags->mTags,
    1414               0 :                              theRootTags->mCount)) {
    1415                 :               // We encountered a tag in root list so fail (we're gated).
    1416               0 :               return eHTMLTag_unknown;
    1417                 :             }
    1418                 : 
    1419                 :             // Otherwise, presume it's something we can simply ignore and
    1420                 :             // continue searching.
    1421                 :           }
    1422                 : 
    1423               0 :           eHTMLTags theTarget = aContext.TagAt(theChildIndex);
    1424               0 :           if (aCurrentTag != theTarget) {
    1425               0 :             aCurrentTag = theTarget;
    1426                 :           }
    1427                 :           // If you make it here, we're ungated and found a target!
    1428               0 :           return aCurrentTag;
    1429              86 :         } else if (theRootTags) {
    1430                 :           // Since we didn't find any close tags, see if there is an instance of
    1431                 :           // aCurrentTag above the stack from the roottag.
    1432              86 :           if (HasCloseablePeerAboveRoot(*theRootTags, aContext, aCurrentTag,
    1433                 :                                         true)) {
    1434              86 :             return aCurrentTag;
    1435                 :           } else {
    1436               0 :             return eHTMLTag_unknown;
    1437                 :           }
    1438                 :         }
    1439                 :       } else {
    1440                 :         // Ok, a much more sensible approach for non-block closers; use the tag
    1441                 :         // group to determine closure: For example: %phrasal closes %phrasal,
    1442                 :         // %fontstyle and %special
    1443               0 :         return gHTMLElements[aCurrentTag].GetCloseTargetForEndTag(aContext,
    1444                 :                                                                   theChildIndex,
    1445               0 :                                                                   aMode);
    1446                 :       }
    1447                 :     }
    1448                 :   }
    1449                 : 
    1450               0 :   return eHTMLTag_unknown;
    1451                 : }
    1452                 : 
    1453                 : static void
    1454               0 : StripWSFollowingTag(eHTMLTags aChildTag, nsITokenizer* aTokenizer,
    1455                 :                     nsTokenAllocator* aTokenAllocator, PRInt32* aNewlineCount)
    1456                 : {
    1457               0 :   if (!aTokenizer || !aTokenAllocator) {
    1458               0 :     return;
    1459                 :   }
    1460                 : 
    1461               0 :   CToken* theToken = aTokenizer->PeekToken();
    1462                 : 
    1463               0 :   PRInt32 newlineCount = 0;
    1464               0 :   while (theToken) {
    1465               0 :     eHTMLTokenTypes theType = eHTMLTokenTypes(theToken->GetTokenType());
    1466                 : 
    1467               0 :     switch(theType) {
    1468                 :       case eToken_newline:
    1469                 :       case eToken_whitespace:
    1470               0 :         theToken = aTokenizer->PopToken();
    1471               0 :         newlineCount += theToken->GetNewlineCount();
    1472               0 :         IF_FREE(theToken, aTokenAllocator);
    1473                 : 
    1474               0 :         theToken = aTokenizer->PeekToken();
    1475               0 :         break;
    1476                 : 
    1477                 :       default:
    1478               0 :         theToken = nsnull;
    1479               0 :         break;
    1480                 :     }
    1481                 :   }
    1482                 : 
    1483               0 :   if (aNewlineCount) {
    1484               0 :     *aNewlineCount += newlineCount;
    1485                 :   }
    1486                 : }
    1487                 : 
    1488                 : /**
    1489                 :  *  This method gets called when an end token has been 
    1490                 :  *  encountered in the parse process. If the end tag matches
    1491                 :  *  the start tag on the stack, then simply close it. Otherwise,
    1492                 :  *  we have a erroneous state condition. This can be because we
    1493                 :  *  have a close tag with no prior open tag (user error) or because
    1494                 :  *  we screwed something up in the parse process. I'm not sure
    1495                 :  *  yet how to tell the difference.
    1496                 :  *  
    1497                 :  *  @param   aToken -- next (start) token to be handled
    1498                 :  *  @return  true if all went well; false if error occurred
    1499                 :  */
    1500                 : nsresult
    1501             344 : CNavDTD::HandleEndToken(CToken* aToken)
    1502                 : {
    1503             344 :   NS_PRECONDITION(nsnull != aToken, kNullToken);
    1504                 : 
    1505             344 :   nsresult    result = NS_OK;
    1506             344 :   eHTMLTags   theChildTag = (eHTMLTags)aToken->GetTypeID();
    1507                 : 
    1508                 :   // Begin by dumping any attributes (bug 143512)
    1509             344 :   CollectAttributes(nsnull, theChildTag, aToken->GetAttributeCount());
    1510                 : 
    1511             344 :   switch (theChildTag) {
    1512                 :     case eHTMLTag_link:
    1513                 :     case eHTMLTag_meta:
    1514               0 :       break;
    1515                 : 
    1516                 :     case eHTMLTag_head:
    1517                 :       StripWSFollowingTag(theChildTag, mTokenizer, mTokenAllocator,
    1518               0 :                           !mCountLines ? nsnull : &mLineNumber);
    1519               0 :       if (mBodyContext->LastOf(eHTMLTag_head) != kNotFound) {
    1520               0 :         result = CloseContainersTo(eHTMLTag_head, false);
    1521                 :       }
    1522               0 :       mFlags &= ~NS_DTD_FLAG_HAS_EXPLICIT_HEAD;
    1523               0 :       break;
    1524                 : 
    1525                 :     case eHTMLTag_form:
    1526               0 :       result = CloseContainer(eHTMLTag_form, false);
    1527               0 :       break;
    1528                 : 
    1529                 :     case eHTMLTag_br:
    1530                 :       {
    1531                 :         // This is special NAV-QUIRKS code that allows users to use </BR>, even
    1532                 :         // though that isn't a legitimate tag.
    1533               0 :         if (eDTDMode_quirks == mDTDMode) {
    1534                 :           // Use recycler and pass the token thro' HandleToken() to fix bugs
    1535                 :           // like 32782.
    1536                 :           CToken* theToken = mTokenAllocator->CreateTokenOfType(eToken_start,
    1537               0 :                                                                 theChildTag);
    1538               0 :           result = HandleToken(theToken);
    1539                 :         }
    1540                 :       }
    1541               0 :       break;
    1542                 : 
    1543                 :     case eHTMLTag_body:
    1544                 :     case eHTMLTag_html:
    1545                 :       StripWSFollowingTag(theChildTag, mTokenizer, mTokenAllocator,
    1546               0 :                           !mCountLines ? nsnull : &mLineNumber);
    1547               0 :       break;
    1548                 : 
    1549                 :     case eHTMLTag_script:
    1550                 :       // Note: we don't fall through to the default case because
    1551                 :       // CloseContainersTo() has the bad habit of closing tags that are opened
    1552                 :       // by document.write(). Fortunately, the tokenizer guarantees that no
    1553                 :       // actual tags appear between <script> and </script> so we won't be
    1554                 :       // closing the wrong tag.
    1555               0 :       if (mBodyContext->Last() != eHTMLTag_script) {
    1556                 :         // Except if we're here, then there's probably a stray script tag.
    1557               0 :         NS_ASSERTION(mBodyContext->LastOf(eHTMLTag_script) == kNotFound,
    1558                 :                      "Mishandling scripts in CNavDTD");
    1559               0 :         break;
    1560                 :       }
    1561                 : 
    1562               0 :       mBodyContext->Pop();
    1563               0 :       result = CloseContainer(eHTMLTag_script, aToken->IsInError());
    1564               0 :       break;
    1565                 : 
    1566                 :     default:
    1567                 :      {
    1568                 :         // Now check to see if this token should be omitted, or
    1569                 :         // if it's gated from closing by the presence of another tag.
    1570             344 :         if (gHTMLElements[theChildTag].CanOmitEndTag()) {
    1571               0 :           PopStyle(theChildTag);
    1572                 :         } else {
    1573             344 :           eHTMLTags theParentTag = mBodyContext->Last();
    1574                 : 
    1575                 :           // First open transient styles, so that we see any autoclosed style
    1576                 :           // tags.
    1577             344 :           if (nsHTMLElement::IsResidualStyleTag(theChildTag)) {
    1578             147 :             result = OpenTransientStyles(theChildTag);
    1579             147 :             if (NS_FAILED(result)) {
    1580               0 :               return result;
    1581                 :             }
    1582                 :           }
    1583                 : 
    1584             344 :           if (kNotFound ==
    1585                 :                 nsHTMLElement::GetIndexOfChildOrSynonym(*mBodyContext,
    1586             344 :                                                         theChildTag)) {
    1587                 :             // Ref: bug 30487
    1588                 :             // Make sure that we don't cross boundaries, of certain elements,
    1589                 :             // to close stylistic information.
    1590                 :             // <font face="helvetica"><table><tr><td></font></td></tr></table> some text...
    1591                 :             // In the above ex. the orphaned FONT tag, inside TD, should cross
    1592                 :             // TD boundary to close the FONT tag above TABLE.
    1593                 :             static eHTMLTags gBarriers[] = {
    1594                 :               eHTMLTag_thead, eHTMLTag_tbody, eHTMLTag_tfoot, eHTMLTag_table
    1595                 :             };
    1596                 : 
    1597               0 :             if (!FindTagInSet(theParentTag, gBarriers,
    1598               0 :                               ArrayLength(gBarriers)) &&
    1599               0 :                 nsHTMLElement::IsResidualStyleTag(theChildTag)) {
    1600                 :               // Fix bug 77746
    1601               0 :               mBodyContext->RemoveStyle(theChildTag);
    1602                 :             }
    1603                 : 
    1604                 :             // If the bit kHandleStrayTag is set then we automatically open up a
    1605                 :             // matching start tag (compatibility).  Currently this bit is set on
    1606                 :             // P tag.  This also fixes Bug: 22623
    1607               0 :             if (gHTMLElements[theChildTag].HasSpecialProperty(kHandleStrayTag) &&
    1608                 :                 mDTDMode != eDTDMode_full_standards &&
    1609                 :                 mDTDMode != eDTDMode_almost_standards) {
    1610                 :               // Oh boy!! we found a "stray" tag. Nav4.x and IE introduce line
    1611                 :               // break in such cases. So, let's simulate that effect for
    1612                 :               // compatibility.
    1613                 :               // Ex. <html><body>Hello</P>There</body></html>
    1614               0 :               PRInt32 theParentContains = -1;
    1615               0 :               if (!CanOmit(theParentTag, theChildTag, theParentContains)) {
    1616                 :                 CToken* theStartToken =
    1617               0 :                   mTokenAllocator->CreateTokenOfType(eToken_start, theChildTag);
    1618               0 :                 NS_ENSURE_TRUE(theStartToken, NS_ERROR_OUT_OF_MEMORY);
    1619                 : 
    1620                 :                 // This check for NS_DTD_FLAG_IN_MISPLACED_CONTENT was added
    1621                 :                 // to fix bug 142965.
    1622               0 :                 if (!(mFlags & NS_DTD_FLAG_IN_MISPLACED_CONTENT)) {
    1623                 :                   // We're not handling misplaced content right now, just push
    1624                 :                   // these new tokens back on the stack and handle them in the
    1625                 :                   // regular flow of HandleToken.
    1626               0 :                   IF_HOLD(aToken);
    1627               0 :                   mTokenizer->PushTokenFront(aToken);
    1628               0 :                   mTokenizer->PushTokenFront(theStartToken);
    1629                 :                 } else {
    1630                 :                   // Oops, we're in misplaced content. Handle these tokens
    1631                 :                   // directly instead of trying to push them onto the tokenizer
    1632                 :                   // stack.
    1633               0 :                   result = HandleToken(theStartToken);
    1634               0 :                   NS_ENSURE_SUCCESS(result, result);
    1635                 : 
    1636               0 :                   IF_HOLD(aToken);
    1637               0 :                   result = HandleToken(aToken);
    1638                 :                 }
    1639                 :               }
    1640                 :             }
    1641               0 :             return result;
    1642                 :           }
    1643             344 :           if (result == NS_OK) {
    1644                 :             eHTMLTags theTarget =
    1645                 :               FindAutoCloseTargetForEndTag(theChildTag, *mBodyContext,
    1646             344 :                                            mDTDMode);
    1647             344 :             if (eHTMLTag_unknown != theTarget) {
    1648             344 :               result = CloseContainersTo(theTarget, false);
    1649                 :             }
    1650                 :           }
    1651                 :         }
    1652                 :       }
    1653             344 :       break;
    1654                 :   }
    1655                 : 
    1656             344 :   return result;
    1657                 : }
    1658                 : 
    1659                 : /**
    1660                 :  * This method will be triggered when the end of a table is
    1661                 :  * encountered.  Its primary purpose is to process all the
    1662                 :  * bad-contents pertaining a particular table. The position
    1663                 :  * of the table is the token bank ID.
    1664                 :  *
    1665                 :  * @update harishd 03/24/99
    1666                 :  * @param  aTag - This ought to be a table tag
    1667                 :  *
    1668                 :  */
    1669                 : nsresult
    1670               0 : CNavDTD::HandleSavedTokens(PRInt32 anIndex)
    1671                 : {
    1672               0 :   NS_PRECONDITION(mBodyContext != nsnull && mBodyContext->GetCount() > 0, "invalid context");
    1673                 : 
    1674               0 :   nsresult  result = NS_OK;
    1675                 : 
    1676               0 :   if (mSink && (anIndex > kNotFound)) {
    1677               0 :     PRInt32 theBadTokenCount = mMisplacedContent.GetSize();
    1678                 : 
    1679               0 :     if (theBadTokenCount > 0) {
    1680               0 :       mFlags |= NS_DTD_FLAG_IN_MISPLACED_CONTENT;
    1681                 : 
    1682               0 :       if (!mTempContext && !(mTempContext = new nsDTDContext())) {
    1683               0 :         return NS_ERROR_OUT_OF_MEMORY;
    1684                 :       }
    1685                 : 
    1686                 :       CToken*   theToken;
    1687                 :       eHTMLTags theTag;
    1688                 :       PRInt32   attrCount;
    1689               0 :       PRInt32   theTopIndex = anIndex + 1;
    1690               0 :       PRInt32   theTagCount = mBodyContext->GetCount();
    1691                 : 
    1692                 :       // Pause the main context and switch to the new context.
    1693               0 :       result = mSink->BeginContext(anIndex);
    1694                 :       
    1695               0 :       NS_ENSURE_SUCCESS(result, result);
    1696                 : 
    1697                 :       // The body context should contain contents only upto the marked position.
    1698               0 :       mBodyContext->MoveEntries(*mTempContext, theTagCount - theTopIndex);
    1699                 : 
    1700                 :       // Now flush out all the bad contents.
    1701               0 :       while (theBadTokenCount-- > 0){
    1702               0 :         theToken = (CToken*)mMisplacedContent.PopFront();
    1703               0 :         if (theToken) {
    1704               0 :           theTag       = (eHTMLTags)theToken->GetTypeID();
    1705               0 :           attrCount    = theToken->GetAttributeCount();
    1706                 :           // Put back attributes, which once got popped out, into the
    1707                 :           // tokenizer.  Make sure we preserve their ordering, however!
    1708                 :           // XXXbz would it be faster to get the tokens out with ObjectAt and
    1709                 :           // put them in the tokenizer and then PopFront them all from
    1710                 :           // mMisplacedContent?
    1711               0 :           nsDeque temp;
    1712               0 :           for (PRInt32 j = 0; j < attrCount; ++j) {
    1713               0 :             CToken* theAttrToken = (CToken*)mMisplacedContent.PopFront();
    1714               0 :             if (theAttrToken) {
    1715               0 :               temp.Push(theAttrToken);
    1716                 :             }
    1717               0 :             theBadTokenCount--;
    1718                 :           }
    1719               0 :           mTokenizer->PrependTokens(temp);
    1720                 : 
    1721               0 :           if (eToken_end == theToken->GetTokenType()) {
    1722                 :             // Ref: Bug 25202
    1723                 :             // Make sure that the BeginContext() is ended only by the call to
    1724                 :             // EndContext(). Ex: <center><table><a></center>.
    1725                 :             // In the Ex. above </center> should not close <center> above table.
    1726                 :             // Doing so will cause the current context to get closed prematurely.
    1727                 :             eHTMLTags closed = FindAutoCloseTargetForEndTag(theTag, *mBodyContext,
    1728               0 :                                                             mDTDMode);
    1729                 :             PRInt32 theIndex = closed != eHTMLTag_unknown
    1730               0 :                                ? mBodyContext->LastOf(closed)
    1731               0 :                                : kNotFound;
    1732                 : 
    1733               0 :             if (theIndex != kNotFound &&
    1734                 :                 theIndex <= mBodyContext->mContextTopIndex) {
    1735               0 :               IF_FREE(theToken, mTokenAllocator);
    1736               0 :               continue;
    1737                 :             }
    1738                 :           }
    1739                 : 
    1740                 :           // XXX This should go away, with this call, it becomes extremely
    1741                 :           // difficult to handle misplaced style and link tags, since it's hard
    1742                 :           // to propagate the block return all the way up and then re-enter this
    1743                 :           // method.
    1744               0 :           result = HandleToken(theToken);
    1745                 :         }
    1746                 :       }
    1747                 : 
    1748               0 :       if (theTopIndex != mBodyContext->GetCount()) {
    1749                 :         // CloseContainersTo does not close any forms we might have opened while
    1750                 :         // handling saved tokens, because the parser does not track forms on its
    1751                 :         // mBodyContext stack.
    1752                 :         CloseContainersTo(theTopIndex, mBodyContext->TagAt(theTopIndex),
    1753               0 :                           true);
    1754                 :       }      
    1755                 : 
    1756                 :       // Bad-contents were successfully processed. Now, itz time to get
    1757                 :       // back to the original body context state.
    1758               0 :       mTempContext->MoveEntries(*mBodyContext, theTagCount - theTopIndex);
    1759                 : 
    1760                 :       // Terminate the new context and switch back to the main context
    1761               0 :       mSink->EndContext(anIndex);
    1762                 : 
    1763               0 :       mFlags &= ~NS_DTD_FLAG_IN_MISPLACED_CONTENT;
    1764                 :     }
    1765                 :   }
    1766               0 :   return result;
    1767                 : }
    1768                 : 
    1769                 : 
    1770                 : /**
    1771                 :  *  This method gets called when an entity token has been 
    1772                 :  *  encountered in the parse process. 
    1773                 :  *  
    1774                 :  *  @update  gess 3/25/98
    1775                 :  *  @param   aToken -- next (start) token to be handled
    1776                 :  *  @return  true if all went well; false if error occurred
    1777                 :  */
    1778                 : nsresult
    1779               0 : CNavDTD::HandleEntityToken(CToken* aToken)
    1780                 : {
    1781               0 :   NS_PRECONDITION(nsnull != aToken, kNullToken);
    1782                 : 
    1783               0 :   nsresult  result = NS_OK;
    1784                 : 
    1785               0 :   const nsSubstring& theStr = aToken->GetStringValue();
    1786                 : 
    1787               0 :   if (kHashsign != theStr.First() &&
    1788               0 :       -1 == nsHTMLEntities::EntityToUnicode(theStr)) {
    1789                 :     // If you're here we have a bogus entity.
    1790                 :     // Convert it into a text token.
    1791                 :     CToken *theToken;
    1792                 : 
    1793               0 :     nsAutoString entityName;
    1794               0 :     entityName.AssignLiteral("&");
    1795               0 :     entityName.Append(theStr);
    1796                 :     theToken = mTokenAllocator->CreateTokenOfType(eToken_text, eHTMLTag_text,
    1797               0 :                                                   entityName);
    1798               0 :     NS_ENSURE_TRUE(theToken, NS_ERROR_OUT_OF_MEMORY);
    1799                 : 
    1800                 :     // theToken should get recycled automagically...
    1801               0 :     return HandleToken(theToken);
    1802                 :   }
    1803                 : 
    1804               0 :   eHTMLTags theParentTag = mBodyContext->Last();
    1805               0 :   nsCParserNode* theNode = mNodeAllocator.CreateNode(aToken, mTokenAllocator);
    1806               0 :   NS_ENSURE_TRUE(theNode, NS_ERROR_OUT_OF_MEMORY);
    1807                 : 
    1808               0 :   PRInt32 theParentContains = -1;
    1809               0 :   if (CanOmit(theParentTag, eHTMLTag_entity, theParentContains)) {
    1810               0 :     eHTMLTags theCurrTag = (eHTMLTags)aToken->GetTypeID();
    1811               0 :     HandleOmittedTag(aToken, theCurrTag, theParentTag, theNode);
    1812                 :   } else {
    1813               0 :     result = AddLeaf(theNode);
    1814                 :   }
    1815               0 :   IF_FREE(theNode, &mNodeAllocator);
    1816               0 :   return result;
    1817                 : }
    1818                 : 
    1819                 : /**
    1820                 :  *  This method gets called when a comment token has been 
    1821                 :  *  encountered in the parse process. After making sure
    1822                 :  *  we're somewhere in the body, we handle the comment
    1823                 :  *  in the same code that we use for text.
    1824                 :  *  
    1825                 :  *  @update  gess 3/25/98
    1826                 :  *  @param   aToken -- next (start) token to be handled
    1827                 :  *  @return  true if all went well; false if error occurred
    1828                 :  */
    1829                 : nsresult
    1830              25 : CNavDTD::HandleCommentToken(CToken* aToken)
    1831                 : {
    1832              25 :   NS_PRECONDITION(nsnull != aToken, kNullToken);
    1833              25 :   return NS_OK;
    1834                 : }
    1835                 : 
    1836                 : 
    1837                 : /**
    1838                 :  *  This method gets called when an attribute token has been
    1839                 :  *  encountered in the parse process. This is an error, since
    1840                 :  *  all attributes should have been accounted for in the prior
    1841                 :  *  start or end tokens
    1842                 :  *
    1843                 :  *  @update  gess 3/25/98
    1844                 :  *  @param   aToken -- next (start) token to be handled
    1845                 :  *  @return  true if all went well; false if error occurred
    1846                 :  */
    1847                 : nsresult
    1848               0 : CNavDTD::HandleAttributeToken(CToken* aToken)
    1849                 : {
    1850               0 :   NS_ERROR("attribute encountered -- this shouldn't happen.");
    1851               0 :   return NS_OK;
    1852                 : }
    1853                 : 
    1854                 : /**
    1855                 :  *  This method gets called when an "instruction" token has been 
    1856                 :  *  encountered in the parse process. 
    1857                 :  *  
    1858                 :  *  @update  gess 3/25/98
    1859                 :  *  @param   aToken -- next (start) token to be handled
    1860                 :  *  @return  true if all went well; false if error occurred
    1861                 :  */
    1862                 : nsresult
    1863               0 : CNavDTD::HandleProcessingInstructionToken(CToken* aToken)
    1864                 : {
    1865               0 :   NS_PRECONDITION(nsnull != aToken, kNullToken);
    1866               0 :   return NS_OK;
    1867                 : }
    1868                 : 
    1869                 : /**
    1870                 :  *  This method gets called when a DOCTYPE token has been 
    1871                 :  *  encountered in the parse process. 
    1872                 :  *  
    1873                 :  *  @update  harishd 09/02/99
    1874                 :  *  @param   aToken -- The very first token to be handled
    1875                 :  *  @return  true if all went well; false if error occurred
    1876                 :  */
    1877                 : nsresult
    1878              25 : CNavDTD::HandleDocTypeDeclToken(CToken* aToken)
    1879                 : {
    1880              25 :   NS_PRECONDITION(nsnull != aToken, kNullToken);
    1881                 : 
    1882              25 :   CDoctypeDeclToken* theToken = static_cast<CDoctypeDeclToken*>(aToken);
    1883              50 :   nsAutoString docTypeStr(theToken->GetStringValue());
    1884                 :   // XXX Doesn't this count the newlines twice?
    1885              25 :   if (mCountLines) {
    1886              25 :     mLineNumber += docTypeStr.CountChar(kNewLine);
    1887                 :   }
    1888                 : 
    1889              25 :   PRInt32 len = docTypeStr.Length();
    1890              25 :   PRInt32 pos = docTypeStr.RFindChar(kGreaterThan);
    1891              25 :   if (pos != kNotFound) {
    1892                 :     // First remove '>' from the end.
    1893              25 :     docTypeStr.Cut(pos, len - pos);
    1894                 :   }
    1895                 : 
    1896                 :   // Now remove "<!" from the begining
    1897              25 :   docTypeStr.Cut(0, 2);
    1898              25 :   theToken->SetStringValue(docTypeStr);
    1899              25 :   return NS_OK;
    1900                 : }
    1901                 : 
    1902                 : /**
    1903                 :  * Retrieve the attributes for this node, and add then into
    1904                 :  * the node.
    1905                 :  *
    1906                 :  * @update  gess4/22/98
    1907                 :  * @param   aNode is the node you want to collect attributes for
    1908                 :  * @param   aCount is the # of attributes you're expecting
    1909                 :  * @return error code (should be 0)
    1910                 :  */
    1911                 : nsresult
    1912             581 : CNavDTD::CollectAttributes(nsIParserNode *aNode, eHTMLTags aTag, PRInt32 aCount)
    1913                 : {
    1914             581 :   int attr = 0;
    1915             581 :   nsresult result = NS_OK;
    1916             581 :   int theAvailTokenCount = mTokenizer->GetCount();
    1917                 : 
    1918             581 :   if (aCount <= theAvailTokenCount) {
    1919                 :     CToken* theToken;
    1920            1313 :     for (attr = 0; attr < aCount; ++attr) {
    1921             732 :       theToken = mTokenizer->PopToken();
    1922             732 :       if (theToken) {
    1923             732 :         eHTMLTokenTypes theType = eHTMLTokenTypes(theToken->GetTokenType());
    1924             732 :         if (theType != eToken_attribute) {
    1925                 :           // If you're here then it means that the token does not
    1926                 :           // belong to this node. Put the token back into the tokenizer
    1927                 :           // and let it go thro' the regular path. Bug: 59189.
    1928               0 :           mTokenizer->PushTokenFront(theToken);
    1929               0 :           break;
    1930                 :         }
    1931                 : 
    1932             732 :         if (mCountLines) {
    1933             732 :           mLineNumber += theToken->GetNewlineCount();
    1934                 :         }
    1935                 : 
    1936             732 :         if (aNode) {
    1937                 :           // If the key is empty, the attribute is unusable, so we should not
    1938                 :           // add it to the node.
    1939             732 :           if (!((CAttributeToken*)theToken)->GetKey().IsEmpty()) {
    1940             732 :             aNode->AddAttribute(theToken);
    1941                 :           } else {
    1942               0 :             IF_FREE(theToken, mTokenAllocator);
    1943                 :           }
    1944                 :         } else {
    1945               0 :           IF_FREE(theToken, mTokenAllocator);
    1946                 :         }
    1947                 :       }
    1948                 :     }
    1949                 :   } else {
    1950               0 :     result = kEOF;
    1951                 :   }
    1952             581 :   return result;
    1953                 : }
    1954                 : 
    1955                 : /** 
    1956                 :  *  This method is called to determine whether or not a tag
    1957                 :  *  of one type can contain a tag of another type.
    1958                 :  *  
    1959                 :  *  @update  gess 4/8/98
    1960                 :  *  @param   aParent -- tag enum of parent container
    1961                 :  *  @param   aChild -- tag enum of child container
    1962                 :  *  @return  true if parent can contain child
    1963                 :  */
    1964                 : NS_IMETHODIMP_(bool)
    1965            3003 : CNavDTD::CanContain(PRInt32 aParent, PRInt32 aChild) const
    1966                 : {
    1967            3003 :   bool result = gHTMLElements[aParent].CanContain((eHTMLTags)aChild, mDTDMode);
    1968                 : 
    1969            3003 :   if (eHTMLTag_nobr == aChild &&
    1970               0 :       IsInlineElement(aParent, aParent) &&
    1971               0 :       HasOpenContainer(eHTMLTag_nobr)) {
    1972               0 :     return false;
    1973                 :   }
    1974                 : 
    1975            3003 :   return result;
    1976                 : }
    1977                 : 
    1978                 : /**
    1979                 :  *  This method is called to determine whether or not
    1980                 :  *  the given childtag is a block element.
    1981                 :  *
    1982                 :  *  @update  gess 6June2000
    1983                 :  *  @param   aChildID -- tag id of child 
    1984                 :  *  @param   aParentID -- tag id of parent (or eHTMLTag_unknown)
    1985                 :  *  @return  true if this tag is a block tag
    1986                 :  */
    1987                 : bool
    1988             330 : CNavDTD::IsBlockElement(PRInt32 aTagID, PRInt32 aParentID) const
    1989                 : {
    1990             330 :   eHTMLTags theTag = (eHTMLTags)aTagID;
    1991                 : 
    1992                 :   return (theTag > eHTMLTag_unknown && theTag < eHTMLTag_userdefined) &&
    1993             330 :           (gHTMLElements[theTag].IsMemberOf(kBlock)        ||
    1994             330 :            gHTMLElements[theTag].IsMemberOf(kBlockEntity)  ||
    1995             269 :            gHTMLElements[theTag].IsMemberOf(kHeading)      ||
    1996             269 :            gHTMLElements[theTag].IsMemberOf(kPreformatted) ||
    1997            1528 :            gHTMLElements[theTag].IsMemberOf(kList));
    1998                 : }
    1999                 : 
    2000                 : /**
    2001                 :  *  This method is called to determine whether or not
    2002                 :  *  the given childtag is an inline element.
    2003                 :  *
    2004                 :  *  @update  gess 6June2000
    2005                 :  *  @param   aChildID -- tag id of child 
    2006                 :  *  @param   aParentID -- tag id of parent (or eHTMLTag_unknown)
    2007                 :  *  @return  true if this tag is an inline tag
    2008                 :  */
    2009                 : bool
    2010              61 : CNavDTD::IsInlineElement(PRInt32 aTagID, PRInt32 aParentID) const
    2011                 : {
    2012              61 :   eHTMLTags theTag = (eHTMLTags)aTagID;
    2013                 : 
    2014                 :   return (theTag > eHTMLTag_unknown && theTag < eHTMLTag_userdefined) &&
    2015              61 :           (gHTMLElements[theTag].IsMemberOf(kInlineEntity) ||
    2016               0 :            gHTMLElements[theTag].IsMemberOf(kFontStyle)    ||
    2017               0 :            gHTMLElements[theTag].IsMemberOf(kPhrase)       ||
    2018               0 :            gHTMLElements[theTag].IsMemberOf(kSpecial)      ||
    2019             122 :            gHTMLElements[theTag].IsMemberOf(kFormControl));
    2020                 : }
    2021                 : 
    2022                 : /**
    2023                 :  *  This method is called to determine whether or not
    2024                 :  *  the necessary intermediate tags should be propagated
    2025                 :  *  between the given parent and given child.
    2026                 :  *
    2027                 :  *  @update  gess 4/8/98
    2028                 :  *  @param   aParent -- tag enum of parent container
    2029                 :  *  @param   aChild -- tag enum of child container
    2030                 :  *  @return  true if propagation should occur
    2031                 :  */
    2032                 : bool
    2033             330 : CNavDTD::CanPropagate(eHTMLTags aParent, eHTMLTags aChild,
    2034                 :                       PRInt32 aParentContains)
    2035                 : {
    2036             330 :   bool result = false;
    2037             330 :   if (aParentContains == -1) {
    2038               0 :     aParentContains = CanContain(aParent, aChild);
    2039                 :   }
    2040                 : 
    2041             330 :   if (aParent == aChild) {
    2042              83 :     return result;
    2043                 :   }
    2044                 : 
    2045             247 :   if (nsHTMLElement::IsContainer(aChild)) {
    2046             247 :     mScratch.Truncate();
    2047             247 :     if (!gHTMLElements[aChild].HasSpecialProperty(kNoPropagate)) {
    2048             172 :       if (nsHTMLElement::IsBlockParent(aParent) ||
    2049              86 :           gHTMLElements[aParent].GetSpecialChildren()) {
    2050               0 :         result = ForwardPropagate(mScratch, aParent, aChild);
    2051               0 :         if (!result) {
    2052               0 :           if (eHTMLTag_unknown != aParent) {
    2053               0 :             result = BackwardPropagate(mScratch, aParent, aChild);
    2054                 :           } else {
    2055               0 :             result = BackwardPropagate(mScratch, eHTMLTag_html, aChild);
    2056                 :           }
    2057                 :         }
    2058                 :       }
    2059                 :     }
    2060             247 :     if (mScratch.Length() - 1 > gHTMLElements[aParent].mPropagateRange) {
    2061             247 :       result = false;
    2062                 :     }
    2063                 :   } else {
    2064               0 :     result = !!aParentContains;
    2065                 :   }
    2066                 : 
    2067                 : 
    2068             247 :   return result;
    2069                 : }
    2070                 : 
    2071                 : 
    2072                 : /**
    2073                 :  *  This method gets called to determine whether a given 
    2074                 :  *  tag can be omitted from opening. Most cannot.
    2075                 :  *  
    2076                 :  *  @param   aParent
    2077                 :  *  @param   aChild
    2078                 :  *  @param   aParentContains
    2079                 :  *  @return  true if given tag can contain other tags
    2080                 :  */
    2081                 : bool
    2082            2147 : CNavDTD::CanOmit(eHTMLTags aParent, eHTMLTags aChild, PRInt32& aParentContains)
    2083                 : {
    2084            2147 :   eHTMLTags theAncestor = gHTMLElements[aChild].mExcludingAncestor;
    2085            2147 :   if (eHTMLTag_unknown != theAncestor && HasOpenContainer(theAncestor)) {
    2086               0 :     return true;
    2087                 :   }
    2088                 : 
    2089            2147 :   theAncestor = gHTMLElements[aChild].mRequiredAncestor;
    2090            2147 :   if (eHTMLTag_unknown != theAncestor) {
    2091                 :     // If there's a required ancestor, we only omit if it isn't open and we
    2092                 :     // can't get to it through propagation.
    2093               0 :     return !HasOpenContainer(theAncestor) &&
    2094               0 :            !CanPropagate(aParent, aChild, aParentContains);
    2095                 :   }
    2096                 : 
    2097            2147 :   if (gHTMLElements[aParent].CanExclude(aChild)) {
    2098               0 :     return true;
    2099                 :   }
    2100                 : 
    2101                 :   // Now the obvious test: if the parent can contain the child, don't omit.
    2102            2147 :   if (-1 == aParentContains) {
    2103               0 :     aParentContains = CanContain(aParent, aChild);
    2104                 :   }
    2105                 : 
    2106            2147 :   if (aParentContains || aChild == aParent) {
    2107            1900 :     return false;
    2108                 :   }
    2109                 : 
    2110             247 :   if (gHTMLElements[aParent].IsBlockEntity() &&
    2111               0 :       nsHTMLElement::IsInlineEntity(aChild)) {
    2112                 :     // Feel free to drop inlines that a block doesn't contain.
    2113               0 :     return true;
    2114                 :   }
    2115                 : 
    2116             247 :   if (gHTMLElements[aParent].HasSpecialProperty(kBadContentWatch)) {
    2117                 :     // We can only omit this child if it does not have the kBadContentWatch
    2118                 :     // special property.
    2119               0 :     return !gHTMLElements[aChild].HasSpecialProperty(kBadContentWatch);
    2120                 :   }
    2121                 : 
    2122             247 :   if (gHTMLElements[aParent].HasSpecialProperty(kSaveMisplaced)) {
    2123               0 :     return true;
    2124                 :   }
    2125                 : 
    2126             247 :   if (aParent == eHTMLTag_body) {
    2127                 :     // There are very few tags that the body does not contain. If we get here
    2128                 :     // the best thing to do is just drop them.
    2129               0 :     return true;
    2130                 :   }
    2131                 : 
    2132             247 :   return false;
    2133                 : }
    2134                 : 
    2135                 : /**
    2136                 :  *  This method gets called to determine whether a given 
    2137                 :  *  tag is itself a container
    2138                 :  *  
    2139                 :  *  @update  gess 4/8/98
    2140                 :  *  @param   aTag -- tag to test as a container
    2141                 :  *  @return  true if given tag can contain other tags
    2142                 :  */
    2143                 : NS_IMETHODIMP_(bool)
    2144               0 : CNavDTD::IsContainer(PRInt32 aTag) const
    2145                 : {
    2146               0 :   return nsHTMLElement::IsContainer((eHTMLTags)aTag);
    2147                 : }
    2148                 : 
    2149                 : 
    2150                 : bool
    2151               0 : CNavDTD::ForwardPropagate(nsString& aSequence, eHTMLTags aParent,
    2152                 :                           eHTMLTags aChild)
    2153                 : {
    2154               0 :   bool result = false;
    2155                 : 
    2156               0 :   switch(aParent) {
    2157                 :     case eHTMLTag_table:
    2158               0 :       if (eHTMLTag_tr == aChild || eHTMLTag_td == aChild) {
    2159               0 :         return BackwardPropagate(aSequence, aParent, aChild);
    2160                 :       }
    2161                 :       // Otherwise, intentionally fall through...
    2162                 : 
    2163                 :     case eHTMLTag_tr:
    2164               0 :       if (CanContain(eHTMLTag_td, aChild)) {
    2165               0 :         aSequence.Append((PRUnichar)eHTMLTag_td);
    2166               0 :         result = BackwardPropagate(aSequence, aParent, eHTMLTag_td);
    2167                 :       }
    2168               0 :       break;
    2169                 : 
    2170                 :     default:
    2171               0 :       break;
    2172                 :   }
    2173                 : 
    2174               0 :   return result;
    2175                 : }
    2176                 : 
    2177                 : bool
    2178               0 : CNavDTD::BackwardPropagate(nsString& aSequence, eHTMLTags aParent,
    2179                 :                            eHTMLTags aChild) const
    2180                 : {
    2181               0 :   eHTMLTags theParent = aParent;
    2182                 : 
    2183               0 :   do {
    2184               0 :     const TagList* theRootTags = gHTMLElements[aChild].GetRootTags();
    2185               0 :     if (!theRootTags) {
    2186               0 :       break;
    2187                 :     }
    2188                 : 
    2189               0 :     theParent = theRootTags->mTags[0];
    2190               0 :     NS_ASSERTION(CanContain(theParent, aChild),
    2191                 :                  "Children must be contained by their root tags");
    2192                 : 
    2193               0 :     aChild = theParent;
    2194               0 :     aSequence.Append((PRUnichar)theParent);
    2195                 :   } while (theParent != eHTMLTag_unknown && theParent != aParent);
    2196                 : 
    2197               0 :   return aParent == theParent;
    2198                 : }
    2199                 : 
    2200             109 : bool CNavDTD::HasOpenContainer(eHTMLTags aContainer) const
    2201                 : {
    2202             109 :   switch (aContainer) {
    2203                 :     case eHTMLTag_form:
    2204               0 :       return !(~mFlags & NS_DTD_FLAG_HAS_OPEN_FORM);
    2205                 :     case eHTMLTag_map:
    2206               0 :       return mOpenMapCount > 0;
    2207                 :     default:
    2208             109 :       return mBodyContext->HasOpenContainer(aContainer);
    2209                 :   }
    2210                 : }
    2211                 : 
    2212                 : bool
    2213              25 : CNavDTD::HasOpenContainer(const eHTMLTags aTagSet[], PRInt32 aCount) const
    2214                 : {
    2215                 :   int theIndex;
    2216              25 :   int theTopIndex = mBodyContext->GetCount() - 1;
    2217                 : 
    2218              50 :   for (theIndex = theTopIndex; theIndex > 0; --theIndex) {
    2219              25 :     if (FindTagInSet((*mBodyContext)[theIndex], aTagSet, aCount)) {
    2220               0 :       return true;
    2221                 :     }
    2222                 :   }
    2223                 : 
    2224              25 :   return false;
    2225                 : }
    2226                 : 
    2227                 : eHTMLTags
    2228               0 : CNavDTD::GetTopNode() const
    2229                 : {
    2230               0 :   return mBodyContext->Last();
    2231                 : }
    2232                 : 
    2233                 : /**
    2234                 :  * It is with great trepidation that I offer this method (privately of course).
    2235                 :  * The gets called whenever a container gets opened. This methods job is to 
    2236                 :  * take a look at the (transient) style stack, and open any style containers that
    2237                 :  * are there. Of course, we shouldn't bother to open styles that are incompatible
    2238                 :  * with our parent container.
    2239                 :  *
    2240                 :  * @update  gess6/4/98
    2241                 :  * @param   tag of the container just opened
    2242                 :  * @return  0 (for now)
    2243                 :  */
    2244                 : nsresult
    2245            1311 : CNavDTD::OpenTransientStyles(eHTMLTags aChildTag, bool aCloseInvalid)
    2246                 : {
    2247            1311 :   nsresult result = NS_OK;
    2248                 : 
    2249                 :   // No need to open transient styles in head context - Fix for 41427
    2250            2192 :   if ((mFlags & NS_DTD_FLAG_ENABLE_RESIDUAL_STYLE) &&
    2251                 :       eHTMLTag_newline != aChildTag &&
    2252             881 :       !(mFlags & NS_DTD_FLAG_HAS_OPEN_HEAD)) {
    2253             856 :     if (CanContain(eHTMLTag_font, aChildTag)) {
    2254             856 :       PRUint32 theCount = mBodyContext->GetCount();
    2255             856 :       PRUint32 theLevel = theCount;
    2256                 : 
    2257                 :       // This first loop is used to determine how far up the containment
    2258                 :       // hierarchy we go looking for residual styles.
    2259            5325 :       while (1 < theLevel) {
    2260            3613 :         eHTMLTags theParentTag = mBodyContext->TagAt(--theLevel);
    2261            3613 :         if (gHTMLElements[theParentTag].HasSpecialProperty(kNoStyleLeaksIn)) {
    2262               0 :           break;
    2263                 :         }
    2264                 :       }
    2265                 : 
    2266             856 :       mFlags &= ~NS_DTD_FLAG_ENABLE_RESIDUAL_STYLE;
    2267            4469 :       for (; theLevel < theCount; ++theLevel) {
    2268            3613 :         nsEntryStack* theStack = mBodyContext->GetStylesAt(theLevel);
    2269            3613 :         if (theStack) {
    2270                 :           // Don't open transient styles if it makes the stack deep, bug 58917.
    2271               0 :           if (theCount + theStack->mCount >= FONTSTYLE_IGNORE_DEPTH) {
    2272               0 :             break;
    2273                 :           }
    2274                 : 
    2275               0 :           PRInt32 sindex = 0;
    2276                 : 
    2277               0 :           nsTagEntry *theEntry = theStack->mEntries;
    2278               0 :           bool isHeadingOpen = HasOpenTagOfType(kHeading, *mBodyContext);
    2279               0 :           for (sindex = 0; sindex < theStack->mCount; ++sindex) {
    2280               0 :             nsCParserNode* theNode = (nsCParserNode*)theEntry->mNode;
    2281               0 :             if (1 == theNode->mUseCount) {
    2282               0 :               eHTMLTags theNodeTag = (eHTMLTags)theNode->GetNodeType();
    2283               0 :               if (gHTMLElements[theNodeTag].CanContain(aChildTag, mDTDMode)) {
    2284                 :                 // XXX The following comment is entirely incoherent.
    2285                 :                 // We do this too, because this entry differs from the new one
    2286                 :                 // we're pushing.
    2287               0 :                 theEntry->mParent = theStack;
    2288               0 :                 if (isHeadingOpen) {
    2289                 :                   // Bug 77352
    2290                 :                   // The style system needs to identify residual style tags
    2291                 :                   // within heading tags so that heading tags' size can take
    2292                 :                   // precedence over the residual style tags' size info..
    2293                 :                   // *Note: Make sure that this attribute is transient since it
    2294                 :                   // should not get carried over to cases other than heading.
    2295               0 :                   CAttributeToken theAttrToken(NS_LITERAL_STRING("_moz-rs-heading"),
    2296               0 :                                                EmptyString());
    2297               0 :                   theNode->AddAttribute(&theAttrToken);
    2298               0 :                   result = OpenContainer(theNode, theNodeTag, theStack);
    2299               0 :                   theNode->PopAttributeToken();
    2300                 :                 } else {
    2301               0 :                   result = OpenContainer(theNode, theNodeTag, theStack);
    2302                 :                 }
    2303               0 :               } else if (aCloseInvalid) {
    2304                 :                 // If the node tag can't contain the child tag, then remove the
    2305                 :                 // child tag from the style stack
    2306               0 :                 nsCParserNode* node = theStack->Remove(sindex, theNodeTag);
    2307               0 :                 IF_FREE(node, &mNodeAllocator);
    2308               0 :                 --theEntry;
    2309                 :               }
    2310                 :             }
    2311               0 :             ++theEntry;
    2312                 :           }
    2313                 :         }
    2314                 :       }
    2315             856 :       mFlags |= NS_DTD_FLAG_ENABLE_RESIDUAL_STYLE;
    2316                 :     }
    2317                 :   }
    2318                 : 
    2319            1311 :   return result;
    2320                 : }
    2321                 : 
    2322                 : /**
    2323                 :  * This method gets called when an explicit style close-tag is encountered.
    2324                 :  * It results in the style tag id being popped from our internal style stack.
    2325                 :  *
    2326                 :  * @update  gess6/4/98
    2327                 :  * @param 
    2328                 :  * @return  0 if all went well (which it always does)
    2329                 :  */
    2330                 : void
    2331               0 : CNavDTD::PopStyle(eHTMLTags aTag)
    2332                 : {
    2333               0 :   if ((mFlags & NS_DTD_FLAG_ENABLE_RESIDUAL_STYLE) &&
    2334               0 :       nsHTMLElement::IsResidualStyleTag(aTag)) {
    2335               0 :     nsCParserNode* node = mBodyContext->PopStyle(aTag);
    2336               0 :     IF_FREE(node, &mNodeAllocator);  
    2337                 :   }
    2338               0 : }
    2339                 : 
    2340                 : 
    2341                 : /**
    2342                 :  * This method does two things: 1st, help construct
    2343                 :  * our own internal model of the content-stack; and
    2344                 :  * 2nd, pass this message on to the sink.
    2345                 :  * 
    2346                 :  * @update  gess4/22/98
    2347                 :  * @param   aNode -- next node to be added to model
    2348                 :  */
    2349                 : nsresult
    2350              28 : CNavDTD::OpenHTML(const nsCParserNode *aNode)
    2351                 : {
    2352              28 :   NS_PRECONDITION(mBodyContext->GetCount() >= 0, kInvalidTagStackPos);
    2353                 : 
    2354              28 :   nsresult result = mSink ? mSink->OpenContainer(*aNode) : NS_OK; 
    2355                 : 
    2356                 :   // Don't push more than one HTML tag into the stack.
    2357              28 :   if (mBodyContext->GetCount() == 0)  {
    2358              28 :     mBodyContext->Push(const_cast<nsCParserNode*>(aNode), 0, false); 
    2359                 :   }
    2360                 : 
    2361              28 :   return result;
    2362                 : }
    2363                 : 
    2364                 : /**
    2365                 :  * This method does two things: 1st, help construct
    2366                 :  * our own internal model of the content-stack; and
    2367                 :  * 2nd, pass this message on to the sink.
    2368                 :  * @update  gess4/6/98
    2369                 :  * @param   aNode -- next node to be added to model
    2370                 :  * @return  TRUE if ok, FALSE if error
    2371                 :  */
    2372                 : nsresult
    2373              28 : CNavDTD::OpenBody(const nsCParserNode *aNode)
    2374                 : {
    2375              28 :   NS_PRECONDITION(mBodyContext->GetCount() >= 0, kInvalidTagStackPos);
    2376                 : 
    2377              28 :   nsresult result = NS_OK;
    2378                 :   
    2379              28 :   if (!(mFlags & NS_DTD_FLAG_HAD_FRAMESET)) {
    2380              28 :     mFlags |= NS_DTD_FLAG_HAD_BODY;
    2381                 : 
    2382                 :     // Make sure the head is closed by the time the body is opened.
    2383              28 :     CloseContainer(eHTMLTag_head, false);
    2384                 : 
    2385                 :     // Now we can open the body.
    2386              28 :     result = mSink ? mSink->OpenContainer(*aNode) : NS_OK; 
    2387                 : 
    2388              28 :     if (!HasOpenContainer(eHTMLTag_body)) {
    2389              28 :       mBodyContext->Push(const_cast<nsCParserNode*>(aNode), 0, false);
    2390              28 :       mTokenizer->PrependTokens(mMisplacedContent);
    2391                 :     }
    2392                 :   }
    2393                 : 
    2394              28 :   return result;
    2395                 : }
    2396                 : 
    2397                 : /**
    2398                 :  * This method does two things: 1st, help construct
    2399                 :  * our own internal model of the content-stack; and
    2400                 :  * 2nd, pass this message on to the sink.
    2401                 :  * @update  gess4/6/98
    2402                 :  * @param   aNode -- next node to be added to model
    2403                 :  * @param   aClosedByStartTag -- ONLY TRUE if the container is being closed by opening of another container.
    2404                 :  * @return  TRUE if ok, FALSE if error
    2405                 :  */
    2406                 : nsresult
    2407             800 : CNavDTD::OpenContainer(const nsCParserNode *aNode,
    2408                 :                        eHTMLTags aTag,
    2409                 :                        nsEntryStack* aStyleStack)
    2410                 : {
    2411             800 :   NS_PRECONDITION(mBodyContext->GetCount() >= 0, kInvalidTagStackPos);
    2412                 : 
    2413             800 :   nsresult   result = NS_OK;
    2414             800 :   bool       done   = true;
    2415             800 :   bool       rs_tag = nsHTMLElement::IsResidualStyleTag(aTag);
    2416                 :   // We need to open transient styles to encompass the <li> so that the bullets
    2417                 :   // inherit the proper colors.
    2418             800 :   bool       li_tag = aTag == eHTMLTag_li;
    2419                 : 
    2420             800 :   if (rs_tag || li_tag) {
    2421                 :     /*
    2422                 :      * Here's an interesting problem:
    2423                 :      *
    2424                 :      * If there's an <a> on the RS-stack, and you're trying to open
    2425                 :      * another <a>, the one on the RS-stack should be discarded.
    2426                 :      *
    2427                 :      * I'm updating OpenTransientStyles to throw old <a>'s away.
    2428                 :      */
    2429             147 :     OpenTransientStyles(aTag, !li_tag);
    2430                 :   }
    2431                 : 
    2432             800 :   switch (aTag) {
    2433                 :     case eHTMLTag_html:
    2434              28 :       result = OpenHTML(aNode);
    2435              28 :       break;
    2436                 : 
    2437                 :     case eHTMLTag_head:
    2438               0 :       if (!(mFlags & NS_DTD_FLAG_HAS_OPEN_HEAD)) {
    2439               0 :         mFlags |= NS_DTD_FLAG_HAS_OPEN_HEAD;
    2440               0 :         done = false;
    2441                 :       }
    2442               0 :       break;
    2443                 : 
    2444                 :     case eHTMLTag_body:
    2445                 :       {
    2446              28 :         eHTMLTags theParent = mBodyContext->Last();
    2447              28 :         if (!gHTMLElements[aTag].IsSpecialParent(theParent)) {
    2448              28 :           mFlags |= NS_DTD_FLAG_HAS_OPEN_BODY;
    2449              28 :           result = OpenBody(aNode);
    2450                 :         } else {
    2451               0 :           done = false;
    2452                 :         }
    2453                 :       }
    2454              28 :       break;
    2455                 : 
    2456                 :     case eHTMLTag_map:
    2457               0 :       ++mOpenMapCount;
    2458               0 :       done = false;
    2459               0 :       break;
    2460                 : 
    2461                 :     case eHTMLTag_form:
    2462                 :       // Discard nested forms - bug 72639
    2463               0 :       if (!(mFlags & NS_DTD_FLAG_HAS_OPEN_FORM)) {
    2464               0 :         mFlags |= NS_DTD_FLAG_HAS_OPEN_FORM;
    2465               0 :         result = mSink ? mSink->OpenContainer(*aNode) : NS_OK;
    2466                 :       }
    2467               0 :       break;
    2468                 : 
    2469                 :     case eHTMLTag_frameset:
    2470                 :       // Make sure that the head is closed before we try to open this frameset.
    2471               0 :       CloseContainer(eHTMLTag_head, false);
    2472                 : 
    2473                 :       // Now that the head is closed, continue on with opening this frameset.
    2474               0 :       mFlags |= NS_DTD_FLAG_HAD_FRAMESET;
    2475               0 :       done = false;
    2476               0 :       break;
    2477                 : 
    2478                 :     case eHTMLTag_noembed:
    2479                 :       // <noembed> is unconditionally alternate content.
    2480               0 :       done = false;
    2481               0 :       mFlags |= NS_DTD_FLAG_ALTERNATE_CONTENT;
    2482               0 :       break;
    2483                 : 
    2484                 :     case eHTMLTag_noscript:
    2485                 :       // We want to make sure that OpenContainer gets called below since we're
    2486                 :       // not doing it here
    2487               0 :       done = false;
    2488                 : 
    2489               0 :       if (mFlags & NS_IPARSER_FLAG_SCRIPT_ENABLED) {
    2490                 :         // XXX This flag doesn't currently do anything (and would be
    2491                 :         // insufficient if it did).
    2492               0 :         mFlags |= NS_DTD_FLAG_ALTERNATE_CONTENT;
    2493                 :       }
    2494               0 :       break;
    2495                 : 
    2496                 :     case eHTMLTag_iframe: // Bug 84491
    2497                 :     case eHTMLTag_noframes:
    2498               0 :       done = false;
    2499               0 :       if (mFlags & NS_IPARSER_FLAG_FRAMES_ENABLED) {
    2500               0 :         mFlags |= NS_DTD_FLAG_ALTERNATE_CONTENT;
    2501                 :       }
    2502               0 :       break;
    2503                 : 
    2504                 :     default:
    2505             744 :       done = false;
    2506             744 :       break;
    2507                 :   }
    2508                 : 
    2509             800 :   if (!done) {
    2510                 : 
    2511             744 :     result = mSink ? mSink->OpenContainer(*aNode) : NS_OK;
    2512                 : 
    2513                 :     // For residual style tags rs_tag will be true and hence
    2514                 :     // the body context will hold an extra reference to the node.
    2515             744 :     mBodyContext->Push(const_cast<nsCParserNode*>(aNode), aStyleStack, rs_tag); 
    2516                 :   }
    2517                 : 
    2518             800 :   return result;
    2519                 : }
    2520                 : 
    2521                 : nsresult
    2522               0 : CNavDTD::CloseResidualStyleTags(const eHTMLTags aTag,
    2523                 :                                 bool aClosedByStartTag)
    2524                 : {
    2525               0 :   const PRInt32 count = mBodyContext->GetCount();
    2526               0 :   PRInt32 pos = count;
    2527               0 :   while (nsHTMLElement::IsResidualStyleTag(mBodyContext->TagAt(pos - 1)))
    2528               0 :     --pos;
    2529               0 :   if (pos < count)
    2530               0 :     return CloseContainersTo(pos, aTag, aClosedByStartTag);
    2531               0 :   return NS_OK;
    2532                 : }
    2533                 : 
    2534                 : /**
    2535                 :  * This method does two things: 1st, help construct
    2536                 :  * our own internal model of the content-stack; and
    2537                 :  * 2nd, pass this message on to the sink.
    2538                 :  * @update  gess4/6/98
    2539                 :  * @param   aTag  -- id of tag to be closed
    2540                 :  * @return  TRUE if ok, FALSE if error
    2541                 :  */
    2542                 : nsresult
    2543             878 : CNavDTD::CloseContainer(const eHTMLTags aTag, bool aMalformed)
    2544                 : {
    2545             878 :   nsresult   result = NS_OK;
    2546             878 :   bool       done   = true;
    2547                 : 
    2548             878 :   switch (aTag) {
    2549                 :     case eHTMLTag_head:
    2550              53 :       if (mFlags & NS_DTD_FLAG_HAS_OPEN_HEAD) {
    2551              25 :         mFlags &= ~NS_DTD_FLAG_HAS_OPEN_HEAD;
    2552              25 :         if (mBodyContext->Last() == eHTMLTag_head) {
    2553               0 :           mBodyContext->Pop();
    2554                 :         } else {
    2555                 :           // This else can happen because CloseContainer is called both directly
    2556                 :           // and from CloseContainersTo. CloseContainersTo pops the current tag
    2557                 :           // off of the stack before calling CloseContainer.
    2558              25 :           NS_ASSERTION(mBodyContext->LastOf(eHTMLTag_head) == kNotFound,
    2559                 :                        "Closing the wrong tag");
    2560                 :         }
    2561              25 :         done = false;
    2562                 :       }
    2563              53 :       break;
    2564                 : 
    2565                 :     case eHTMLTag_map:
    2566               0 :       if (mOpenMapCount) {
    2567               0 :         mOpenMapCount--;
    2568               0 :         done = false;
    2569                 :       }
    2570               0 :       break;
    2571                 : 
    2572                 :     case eHTMLTag_form:
    2573               0 :       if (mFlags & NS_DTD_FLAG_HAS_OPEN_FORM) {
    2574               0 :         mFlags &= ~NS_DTD_FLAG_HAS_OPEN_FORM;
    2575               0 :         done = false;
    2576                 :         // If we neglect to close these tags, the sink will refuse to close the
    2577                 :         // form because the form will not be on the top of the SinkContext stack.
    2578                 :         // See HTMLContentSink::CloseForm.  (XXX do this in other cases?)
    2579               0 :         CloseResidualStyleTags(eHTMLTag_form, false);
    2580                 :       }
    2581               0 :       break;
    2582                 : 
    2583                 :     case eHTMLTag_iframe:
    2584                 :     case eHTMLTag_noembed:
    2585                 :     case eHTMLTag_noscript:
    2586                 :     case eHTMLTag_noframes:
    2587                 :       // Switch from alternate content state to regular state.
    2588               0 :       mFlags &= ~NS_DTD_FLAG_ALTERNATE_CONTENT;
    2589                 : 
    2590                 :       // falling thro' intentionally....
    2591                 :     default:
    2592             825 :       done = false;
    2593                 :   }
    2594                 : 
    2595             878 :   if (!done) {
    2596                 : 
    2597             850 :     if (mSink) {
    2598             850 :       result = !aMalformed
    2599             850 :                ? mSink->CloseContainer(aTag)
    2600            1700 :                : mSink->CloseMalformedContainer(aTag);
    2601                 :     }
    2602                 : 
    2603                 :     // If we were dealing with a head container in the body, make sure to
    2604                 :     // close the head context now, so that body content doesn't get sucked
    2605                 :     // into the head.
    2606             850 :     if (mBodyContext->GetCount() == mHeadContainerPosition) {
    2607               0 :       mHeadContainerPosition = -1;
    2608               0 :       nsresult headresult = CloseContainer(eHTMLTag_head, false);
    2609                 : 
    2610                 :       // Note: we could be assigning NS_OK into NS_OK here, but that's ok.
    2611                 :       // This test is to avoid a successful CloseHead result stomping over a
    2612                 :       // request to block the parser.
    2613               0 :       if (NS_SUCCEEDED(result)) {
    2614               0 :         result = headresult;
    2615                 :       }
    2616                 :     }
    2617                 :   }
    2618                 : 
    2619             878 :   return result;
    2620                 : }
    2621                 : 
    2622                 : /**
    2623                 :  * This method does two things: 1st, help construct
    2624                 :  * our own internal model of the content-stack; and
    2625                 :  * 2nd, pass this message on to the sink.
    2626                 :  * @update  gess4/6/98
    2627                 :  * @param   anIndex
    2628                 :  * @param   aTag
    2629                 :  * @param   aClosedByStartTag -- if TRUE, then we're closing something because a start tag caused it
    2630                 :  * @return  TRUE if ok, FALSE if error
    2631                 :  */
    2632                 : nsresult
    2633             755 : CNavDTD::CloseContainersTo(PRInt32 anIndex, eHTMLTags aTarget,
    2634                 :                            bool aClosedByStartTag)
    2635                 : {
    2636             755 :   NS_PRECONDITION(mBodyContext->GetCount() > 0, kInvalidTagStackPos);
    2637             755 :   nsresult result = NS_OK;
    2638                 : 
    2639             755 :   if (anIndex < mBodyContext->GetCount() && anIndex >= 0) {
    2640             755 :     PRInt32 count = 0;
    2641            2360 :     while ((count = mBodyContext->GetCount()) > anIndex) {
    2642             850 :       nsEntryStack* theChildStyleStack = 0;
    2643             850 :       eHTMLTags theTag = mBodyContext->Last();
    2644             850 :       nsCParserNode* theNode = mBodyContext->Pop(theChildStyleStack);
    2645             850 :       result = CloseContainer(theTag, false);
    2646                 : 
    2647             850 :       bool theTagIsStyle = nsHTMLElement::IsResidualStyleTag(theTag);
    2648                 :       // If the current tag cannot leak out then we shouldn't leak out of the target - Fix 40713
    2649             850 :       bool theStyleDoesntLeakOut = gHTMLElements[theTag].HasSpecialProperty(kNoStyleLeaksOut);
    2650             850 :       if (!theStyleDoesntLeakOut) {
    2651             850 :         theStyleDoesntLeakOut = gHTMLElements[aTarget].HasSpecialProperty(kNoStyleLeaksOut);
    2652                 :       }
    2653                 : 
    2654                 :       // Do not invoke residual style handling when dealing with
    2655                 :       // alternate content. This fixed bug 25214.
    2656             850 :       if (theTagIsStyle && !(mFlags & NS_DTD_FLAG_ALTERNATE_CONTENT)) {
    2657             147 :         NS_ASSERTION(theNode, "residual style node should not be null");
    2658             147 :         if (!theNode) {
    2659               0 :           if (theChildStyleStack) {
    2660               0 :             mBodyContext->PushStyles(theChildStyleStack);
    2661                 :           }
    2662               0 :           return NS_OK;
    2663                 :         }
    2664                 : 
    2665             147 :         bool theTargetTagIsStyle = nsHTMLElement::IsResidualStyleTag(aTarget);
    2666             147 :         if (aClosedByStartTag) {
    2667                 :           // Handle closure due to new start tag.
    2668                 :           // The cases we're handing here:
    2669                 :           // 1. <body><b><DIV>       //<b> gets pushed onto <body>.mStyles.
    2670                 :           // 2. <body><a>text<a>     //in this case, the target matches, so don't push style
    2671               0 :           if (theNode->mUseCount == 0) {
    2672               0 :             if (theTag != aTarget) {
    2673               0 :               if (theChildStyleStack) {
    2674               0 :                 theChildStyleStack->PushFront(theNode);
    2675                 :               } else {
    2676               0 :                 mBodyContext->PushStyle(theNode);
    2677                 :               }
    2678                 :             }
    2679               0 :           } else if (theTag == aTarget && !gHTMLElements[aTarget].CanContainSelf()) {
    2680                 :             //here's a case we missed:  <a><div>text<a>text</a></div>
    2681                 :             //The <div> pushes the 1st <a> onto the rs-stack, then the 2nd <a>
    2682                 :             //pops the 1st <a> from the rs-stack altogether.
    2683               0 :             nsCParserNode* node = mBodyContext->PopStyle(theTag);
    2684               0 :             IF_FREE(node, &mNodeAllocator);
    2685                 :           }
    2686                 : 
    2687               0 :           if (theChildStyleStack) {
    2688               0 :             mBodyContext->PushStyles(theChildStyleStack);
    2689                 :           }
    2690                 :         } else {
    2691                 :           /*
    2692                 :            * if you're here, then we're dealing with the closure of tags
    2693                 :            * caused by a close tag (as opposed to an open tag).
    2694                 :            * At a minimum, we should consider pushing residual styles up
    2695                 :            * up the stack or popping and recycling displaced nodes.
    2696                 :            *
    2697                 :            * Known cases:
    2698                 :            * 1. <body><b><div>text</DIV>
    2699                 :            * Here the <b> will leak into <div> (see case given above), and
    2700                 :            * when <div> closes the <b> is dropped since it's already residual.
    2701                 :            *
    2702                 :            * 2. <body><div><b>text</div>
    2703                 :            * Here the <b> will leak out of the <div> and get pushed onto
    2704                 :            * the RS stack for the <body>, since it originated in the <div>.
    2705                 :            *
    2706                 :            * 3. <body><span><b>text</span>
    2707                 :            * In this case, the the <b> get's pushed onto the style stack.
    2708                 :            * Later we deal with RS styles stored on the <span>
    2709                 :            *
    2710                 :            * 4. <body><span><b>text</i>
    2711                 :            * Here we the <b>is closed by a (synonymous) style tag.
    2712                 :            * In this case, the <b> is simply closed.
    2713                 :            */
    2714             147 :           if (theChildStyleStack) {
    2715               0 :             if (!theStyleDoesntLeakOut) {
    2716               0 :               if (theTag != aTarget) {
    2717               0 :                 if (theNode->mUseCount == 0) {
    2718               0 :                   theChildStyleStack->PushFront(theNode);
    2719                 :                 }
    2720               0 :               } else if (theNode->mUseCount == 1) {
    2721                 :                 // This fixes bug 30885,29626.
    2722                 :                 // Make sure that the node, which is about to
    2723                 :                 // get released does not stay on the style stack...
    2724                 :                 // Also be sure to remove the correct style off the
    2725                 :                 // style stack. -  Ref. bug 94208.
    2726                 :                 // Ex <FONT><B><I></FONT><FONT></B></I></FONT>
    2727                 :                 // Make sure that </B> removes B off the style stack.
    2728               0 :                 mBodyContext->RemoveStyle(theTag);
    2729                 :               }
    2730               0 :               mBodyContext->PushStyles(theChildStyleStack);
    2731                 :             } else{
    2732               0 :               IF_DELETE(theChildStyleStack, &mNodeAllocator);
    2733                 :             }
    2734             147 :           } else if (theNode->mUseCount == 0) {
    2735                 :             // The old version of this only pushed if the targettag wasn't
    2736                 :             // style.  But that misses this case: <font><b>text</font>, where
    2737                 :             // the b should leak.
    2738             147 :             if (aTarget != theTag) {
    2739               0 :               mBodyContext->PushStyle(theNode);
    2740                 :             }
    2741                 :           } else {
    2742                 :             // Ah, at last, the final case. If you're here, then we just popped
    2743                 :             // a style tag that got onto that tag stack from a stylestack
    2744                 :             // somewhere.  Pop it from the stylestack if the target is also a
    2745                 :             // style tag.  Make sure to remove the matching style. In the
    2746                 :             // following example:
    2747                 :             // <FONT><B><I></FONT><FONT color=red></B></I></FONT>
    2748                 :             // make sure that </I> does not remove
    2749                 :             // <FONT color=red> off the style stack. - bug 94208
    2750               0 :             if (theTargetTagIsStyle && theTag == aTarget) {
    2751               0 :               mBodyContext->RemoveStyle(theTag);
    2752                 :             }
    2753                 :           }
    2754             147 :         }
    2755                 :       } else {
    2756                 :         // The tag is not a style tag.
    2757             703 :         if (theChildStyleStack) {
    2758               0 :           if (theStyleDoesntLeakOut) {
    2759               0 :             IF_DELETE(theChildStyleStack, &mNodeAllocator);
    2760                 :           } else {
    2761               0 :             mBodyContext->PushStyles(theChildStyleStack);
    2762                 :           }
    2763                 :         }
    2764                 :       }
    2765             850 :       IF_FREE(theNode, &mNodeAllocator);
    2766                 :     }
    2767                 :   }
    2768             755 :   return result;
    2769                 : }
    2770                 : 
    2771                 : /**
    2772                 :  * This method does two things: 1st, help construct
    2773                 :  * our own internal model of the content-stack; and
    2774                 :  * 2nd, pass this message on to the sink.
    2775                 :  * @update  gess4/6/98
    2776                 :  * @param   aTag --
    2777                 :  * @param   aClosedByStartTag -- ONLY TRUE if the container is being closed by opening of another container.
    2778                 :  * @return  TRUE if ok, FALSE if error
    2779                 :  */
    2780                 : nsresult
    2781             425 : CNavDTD::CloseContainersTo(eHTMLTags aTag, bool aClosedByStartTag)
    2782                 : {
    2783             425 :   NS_PRECONDITION(mBodyContext->GetCount() > 0, kInvalidTagStackPos);
    2784                 : 
    2785             425 :   PRInt32 pos = mBodyContext->LastOf(aTag);
    2786                 : 
    2787             425 :   if (kNotFound != pos) {
    2788                 :     // The tag is indeed open, so close it.
    2789             425 :     return CloseContainersTo(pos, aTag, aClosedByStartTag);
    2790                 :   }
    2791                 : 
    2792               0 :   eHTMLTags theTopTag = mBodyContext->Last();
    2793                 : 
    2794               0 :   bool theTagIsSynonymous = (nsHTMLElement::IsResidualStyleTag(aTag) &&
    2795               0 :                                nsHTMLElement::IsResidualStyleTag(theTopTag)) ||
    2796               0 :                               (gHTMLElements[aTag].IsMemberOf(kHeading) &&
    2797               0 :                                gHTMLElements[theTopTag].IsMemberOf(kHeading));
    2798                 : 
    2799               0 :   if (theTagIsSynonymous) {
    2800                 :     // If you're here, it's because we're trying to close one tag,
    2801                 :     // but a different (synonymous) one is actually open. Because this is NAV4x
    2802                 :     // compatibililty mode, we must close the one that's really open.
    2803               0 :     aTag = theTopTag;
    2804               0 :     pos = mBodyContext->LastOf(aTag);
    2805               0 :     if (kNotFound != pos) {
    2806                 :       // The tag is indeed open, so close it.
    2807               0 :       return CloseContainersTo(pos, aTag, aClosedByStartTag);
    2808                 :     }
    2809                 :   }
    2810                 : 
    2811               0 :   nsresult result = NS_OK;
    2812               0 :   const TagList* theRootTags = gHTMLElements[aTag].GetRootTags();
    2813                 :   // XXX Can we just bail if !theRootTags? Does that ever happen?
    2814               0 :   eHTMLTags theParentTag = theRootTags ? theRootTags->mTags[0] : eHTMLTag_unknown;
    2815               0 :   pos = mBodyContext->LastOf(theParentTag);
    2816               0 :   if (kNotFound != pos) {
    2817                 :     // The parent container is open, so close it instead
    2818               0 :     result = CloseContainersTo(pos + 1, aTag, aClosedByStartTag);
    2819                 :   }
    2820               0 :   return result;
    2821                 : }
    2822                 : 
    2823                 : /**
    2824                 :  * This method does two things: 1st, help construct
    2825                 :  * our own internal model of the content-stack; and
    2826                 :  * 2nd, pass this message on to the sink.
    2827                 :  * @update  gess4/6/98
    2828                 :  * @param   aNode -- next node to be added to model
    2829                 :  * @return  error code; 0 means OK
    2830                 :  */
    2831                 : nsresult
    2832            1017 : CNavDTD::AddLeaf(const nsIParserNode *aNode)
    2833                 : {
    2834            1017 :   nsresult result = NS_OK;
    2835                 : 
    2836            1017 :   if (mSink) {
    2837            1017 :     eHTMLTags theTag = (eHTMLTags)aNode->GetNodeType();
    2838            1017 :     OpenTransientStyles(theTag);
    2839                 : 
    2840            1017 :     result = mSink->AddLeaf(*aNode);
    2841                 :   }
    2842                 : 
    2843            1017 :   return result;
    2844                 : }
    2845                 : 
    2846                 : /**
    2847                 :  * Call this method ONLY when you want to write a leaf
    2848                 :  * into the head container.
    2849                 :  * 
    2850                 :  * @update  gess 03/14/99
    2851                 :  * @param   aNode -- next node to be added to model
    2852                 :  * @return  error code; 0 means OK
    2853                 :  */
    2854                 : nsresult
    2855             150 : CNavDTD::AddHeadContent(nsIParserNode *aNode)
    2856                 : {
    2857             150 :   nsresult result = NS_OK;
    2858                 : 
    2859                 :   static eHTMLTags gNoXTags[] = { eHTMLTag_noembed, eHTMLTag_noframes };
    2860                 : 
    2861             150 :   eHTMLTags theTag = (eHTMLTags)aNode->GetNodeType();
    2862                 : 
    2863                 :   // XXX - SCRIPT inside NOTAGS should not get executed unless the pref.
    2864                 :   // says so.  Since we don't have this support yet..lets ignore the
    2865                 :   // SCRIPT inside NOTAGS.  Ref Bug 25880.
    2866             150 :   if (eHTMLTag_meta == theTag || eHTMLTag_script == theTag) {
    2867              25 :     if (HasOpenContainer(gNoXTags, ArrayLength(gNoXTags))) {
    2868               0 :       return result;
    2869                 :     }
    2870                 :   }
    2871                 : 
    2872             150 :   if (mSink) {
    2873                 :     // Make sure the head is opened.
    2874             150 :     if (!(mFlags & NS_DTD_FLAG_HAS_OPEN_HEAD)) {
    2875              25 :       result = mSink->OpenHead();
    2876              25 :       mBodyContext->PushTag(eHTMLTag_head);
    2877              25 :       mFlags |= NS_DTD_FLAG_HAS_OPEN_HEAD;
    2878                 :     }
    2879                 : 
    2880                 :     // Note: userdefined tags in the head are treated as leaves.
    2881             150 :     if (!nsHTMLElement::IsContainer(theTag) || theTag == eHTMLTag_userdefined) {
    2882             125 :       result = mSink->AddLeaf(*aNode);
    2883                 : 
    2884             125 :       if (mFlags & NS_DTD_FLAG_HAS_MAIN_CONTAINER) {
    2885                 :         // Close the head now so that body content doesn't get sucked into it.
    2886               0 :         CloseContainer(eHTMLTag_head, false);
    2887                 :       }
    2888                 :     } else {
    2889              25 :       if ((mFlags & NS_DTD_FLAG_HAS_MAIN_CONTAINER) &&
    2890                 :           mHeadContainerPosition == -1) {
    2891                 :         // Keep track of this so that we know when to close the head, when
    2892                 :         // this tag is done with.
    2893               0 :         mHeadContainerPosition = mBodyContext->GetCount();
    2894                 :       }
    2895                 : 
    2896                 :       // Note: The head context is already opened.
    2897              25 :       result = mSink->OpenContainer(*aNode);
    2898                 : 
    2899                 :       mBodyContext->Push(static_cast<nsCParserNode*>(aNode), nsnull,
    2900              25 :                          false);
    2901                 :     }
    2902                 :   }
    2903                 : 
    2904             150 :   return result;
    2905                 : }
    2906                 : 
    2907                 : void
    2908               0 : CNavDTD::CreateContextStackFor(eHTMLTags aParent, eHTMLTags aChild)
    2909                 : {
    2910               0 :   mScratch.Truncate();
    2911                 : 
    2912               0 :   bool      result = ForwardPropagate(mScratch, aParent, aChild);
    2913                 : 
    2914               0 :   if (!result) {
    2915               0 :     if (eHTMLTag_unknown == aParent) {
    2916               0 :       result = BackwardPropagate(mScratch, eHTMLTag_html, aChild);
    2917               0 :     } else if (aParent != aChild) {
    2918                 :       // Don't even bother if we're already inside a similar element...
    2919               0 :       result = BackwardPropagate(mScratch, aParent, aChild);
    2920                 :     }
    2921                 :   }
    2922                 : 
    2923               0 :   if (!result) {
    2924               0 :     return;
    2925                 :   }
    2926                 : 
    2927               0 :   PRInt32   theLen = mScratch.Length();
    2928               0 :   eHTMLTags theTag = (eHTMLTags)mScratch[--theLen];
    2929                 : 
    2930                 :   // Now, build up the stack according to the tags.
    2931               0 :   while (theLen) {
    2932               0 :     theTag = (eHTMLTags)mScratch[--theLen];
    2933                 : 
    2934                 :     // Note: These tokens should all wind up on contextstack, so don't recycle
    2935                 :     // them.
    2936               0 :     CToken *theToken = mTokenAllocator->CreateTokenOfType(eToken_start, theTag);
    2937               0 :     HandleToken(theToken);
    2938                 :   }
    2939            4392 : }

Generated by: LCOV version 1.7