imported patch parser-own-dtd.diff
authorBen Newman <bnewman@mozilla.com>
Mon, 23 Mar 2009 18:26:46 -0700
changeset 26491 365c68acba58a50a15a8601cfca04fc3f54cac6c
parent 26490 0832dd8ea2b7e6a40c1565f1ac7815db0b43e2f5
child 26492 8f9ff81ef3fa875ac4ec7d7edb6ab46aa395e630
push id6101
push userbnewman@mozilla.com
push dateTue, 24 Mar 2009 01:27:23 +0000
treeherdermozilla-central@c0fad0d1535d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone1.9.2a1pre
imported patch parser-own-dtd.diff
parser/htmlparser/src/CParserContext.cpp
parser/htmlparser/src/CParserContext.h
parser/htmlparser/src/nsParser.cpp
parser/htmlparser/src/nsParser.h
--- a/parser/htmlparser/src/CParserContext.cpp
+++ b/parser/htmlparser/src/CParserContext.cpp
@@ -39,27 +39,26 @@
 
 #include "nsIAtom.h"
 #include "CParserContext.h"
 #include "nsToken.h"
 #include "prenv.h"  
 #include "nsIHTMLContentSink.h"
 #include "nsHTMLTokenizer.h"
 
-CParserContext::CParserContext(nsScanner* aScanner, 
+CParserContext::CParserContext(CParserContext* aPrevContext,
+                               nsScanner* aScanner, 
                                void *aKey, 
                                eParserCommands aCommand,
                                nsIRequestObserver* aListener, 
-                               nsIDTD *aDTD, 
                                eAutoDetectResult aStatus, 
                                PRBool aCopyUnused)
-  : mDTD(aDTD),
-    mListener(aListener),
+  : mListener(aListener),
     mKey(aKey),
-    mPrevContext(nsnull),
+    mPrevContext(aPrevContext),
     mScanner(aScanner),
     mDTDMode(eDTDMode_unknown),
     mStreamListenerState(eNone),
     mContextType(eCTNone),
     mAutoDetectStatus(aStatus),
     mParserCommand(aCommand),
     mMultipart(PR_TRUE),
     mCopyUnused(aCopyUnused),
@@ -91,24 +90,25 @@ CParserContext::SetMimeType(const nsACSt
            mMimeType.EqualsLiteral(kSVGTextContentType)          ||
 #endif
            mMimeType.EqualsLiteral(kRDFApplicationContentType)   ||
            mMimeType.EqualsLiteral(kRDFTextContentType))
     mDocType = eXML;
 }
 
 nsresult
-CParserContext::GetTokenizer(PRInt32 aType,
+CParserContext::GetTokenizer(nsIDTD* aDTD,
                              nsIContentSink* aSink,
                              nsITokenizer*& aTokenizer)
 {
   nsresult result = NS_OK;
-  
+  PRInt32 type = aDTD ? aDTD->GetType() : NS_IPARSER_FLAG_HTML;
+
   if (!mTokenizer) {
-    if (aType == NS_IPARSER_FLAG_HTML || mParserCommand == eViewSource) {
+    if (type == NS_IPARSER_FLAG_HTML || mParserCommand == eViewSource) {
       nsCOMPtr<nsIHTMLContentSink> theSink = do_QueryInterface(aSink);
       PRUint16 theFlags = 0;
 
       if (theSink) {
         // XXX This code is repeated both here and in CNavDTD. Can the two
         // callsites be combined?
         PRBool enabled;
         theSink->IsEnabled(eHTMLTag_frameset, &enabled);
@@ -129,17 +129,17 @@ CParserContext::GetTokenizer(PRInt32 aTy
       }
 
       // Make sure the new tokenizer has all of the necessary information.
       // XXX this might not be necessary.
       if (mPrevContext) {
         mTokenizer->CopyState(mPrevContext->mTokenizer);
       }
     }
-    else if (aType == NS_IPARSER_FLAG_XML) {
-      mTokenizer = do_QueryInterface(mDTD, &result);
+    else if (type == NS_IPARSER_FLAG_XML) {
+      mTokenizer = do_QueryInterface(aDTD, &result);
     }
   }
-  
+
   aTokenizer = mTokenizer;
 
   return result;
 }
--- a/parser/htmlparser/src/CParserContext.h
+++ b/parser/htmlparser/src/CParserContext.h
@@ -58,38 +58,37 @@
  * Note that the parser is given FULL access to all
  * data in a parsercontext. Hey, that what it's for!
  */
 
 class CParserContext {
 public:
    enum eContextType {eCTNone,eCTURL,eCTString,eCTStream};
 
-   CParserContext(nsScanner* aScanner,
+   CParserContext(CParserContext* aPrevContext,
+                  nsScanner* aScanner,
                   void* aKey = 0,
                   eParserCommands aCommand = eViewNormal,
                   nsIRequestObserver* aListener = 0,
-                  nsIDTD* aDTD = 0,
                   eAutoDetectResult aStatus = eUnknownDetect,
                   PRBool aCopyUnused = PR_FALSE);
 
     ~CParserContext();
 
-    nsresult GetTokenizer(PRInt32 aType,
+    nsresult GetTokenizer(nsIDTD* aDTD,
                           nsIContentSink* aSink,
                           nsITokenizer*& aTokenizer);
     void  SetMimeType(const nsACString& aMimeType);
 
     nsCOMPtr<nsIRequest> mRequest; // provided by necko to differnciate different input streams
                                    // why is mRequest strongly referenced? see bug 102376.
-    nsCOMPtr<nsIDTD>     mDTD;
     nsCOMPtr<nsIRequestObserver> mListener;
-    void*                mKey;
+    void* const          mKey;
     nsCOMPtr<nsITokenizer> mTokenizer;
-    CParserContext*      mPrevContext;
+    CParserContext* const mPrevContext;
     nsAutoPtr<nsScanner> mScanner;
 
     nsCString            mMimeType;
     nsDTDMode            mDTDMode;
 
     eParserDocType       mDocType;
     eStreamState         mStreamListenerState;
     eContextType         mContextType;
--- a/parser/htmlparser/src/nsParser.cpp
+++ b/parser/htmlparser/src/nsParser.cpp
@@ -854,26 +854,27 @@ nsParser::Cleanup()
     mSpeculativeScriptThread->Terminate();
     mSpeculativeScriptThread = nsnull;
   }
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsParser)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsParser)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDTD)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mSink)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mObserver)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsParser)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDTD)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mSink)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mObserver)
   CParserContext *pc = tmp->mParserContext;
   while (pc) {
-    cb.NoteXPCOMChild(pc->mDTD);
     cb.NoteXPCOMChild(pc->mTokenizer);
     pc = pc->mPrevContext;
   }
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsParser, nsIParser)
 NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsParser, nsIParser)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsParser)
@@ -1429,43 +1430,38 @@ DetermineParseMode(const nsString& aBuff
     aDocType = ePlainText;
     aParseMode = eDTDMode_quirks;
   } else { // Some form of XML
     aDocType = eXML;
     aParseMode = eDTDMode_full_standards;
   }
 }
 
-static nsresult
+static nsIDTD*
 FindSuitableDTD(CParserContext& aParserContext)
 {
-  NS_ASSERTION(!aParserContext.mDTD, "Already found a DTD");
-
   // We always find a DTD.
   aParserContext.mAutoDetectStatus = ePrimaryDetect;
 
 #ifdef MOZ_VIEW_SOURCE
   // Quick check for view source.
   if (aParserContext.mParserCommand == eViewSource) {
-    aParserContext.mDTD = new CViewSourceHTML();
-    return aParserContext.mDTD ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
+    return new CViewSourceHTML();
   }
 #endif
 
   // Now see if we're parsing HTML (which, as far as we're concerned, simply
   // means "not XML").
   if (aParserContext.mDocType != eXML) {
-    aParserContext.mDTD = new CNavDTD();
-    return aParserContext.mDTD ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
+    return new CNavDTD();
   }
 
   // If we're here, then we'd better be parsing XML.
   NS_ASSERTION(aParserContext.mDocType == eXML, "What are you trying to send me, here?");
-  aParserContext.mDTD = new nsExpatDriver();
-  return aParserContext.mDTD ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
+  return new nsExpatDriver();
 }
 
 NS_IMETHODIMP
 nsParser::CancelParsingEvents()
 {
   if (mFlags & NS_PARSER_FLAG_PENDING_CONTINUE_EVENT) {
     NS_ASSERTION(mContinueEvent, "mContinueEvent is null");
     // Revoke the pending continue parsing event
@@ -1501,24 +1497,26 @@ nsParser::WillBuildModel(nsString& aFile
 
     // Grab 1024 characters, starting at the first non-whitespace
     // character, to look for the doctype in.
     mParserContext->mScanner->Peek(theBuffer, 1024, mParserContext->mScanner->FirstNonWhitespacePosition());
     DetermineParseMode(theBuffer, mParserContext->mDTDMode,
                        mParserContext->mDocType, mParserContext->mMimeType);
   }
 
-  nsresult rv = FindSuitableDTD(*mParserContext);
-  NS_ENSURE_SUCCESS(rv, rv);
+  NS_ASSERTION(!mDTD || !mParserContext->mPrevContext,
+               "Clobbering DTD for non-root parser context!");
+  mDTD = FindSuitableDTD(*mParserContext);
+  NS_ENSURE_TRUE(mDTD, NS_ERROR_OUT_OF_MEMORY);
 
   nsITokenizer* tokenizer;
-  rv = mParserContext->GetTokenizer(mParserContext->mDTD->GetType(), mSink, tokenizer);
+  nsresult rv = mParserContext->GetTokenizer(mDTD, mSink, tokenizer);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  return mParserContext->mDTD->WillBuildModel(*mParserContext, tokenizer, mSink);
+  return mDTD->WillBuildModel(*mParserContext, tokenizer, mSink);
 }
 
 /**
  * This gets called when the parser is done with its input.
  * Note that the parser may have been called recursively, so we
  * have to check for a prev. context before closing out the DTD/sink.
  */
 nsresult
@@ -1526,19 +1524,19 @@ nsParser::DidBuildModel(nsresult anError
 {
   nsresult result = anErrorCode;
 
   if (IsComplete()) {
     if (mParserContext && !mParserContext->mPrevContext) {
       // Let sink know if we're about to end load because we've been terminated.
       // In that case we don't want it to run deferred scripts.
       PRBool terminated = mInternalState == NS_ERROR_HTMLPARSER_STOPPARSING;
-      if (mParserContext->mDTD && mSink &&
+      if (mDTD && mSink &&
           mSink->ReadyToCallDidBuildModel(terminated)) {
-        result = mParserContext->mDTD->DidBuildModel(anErrorCode,PR_TRUE,this,mSink);
+        result = mDTD->DidBuildModel(anErrorCode,PR_TRUE,this,mSink);
       }
 
       //Ref. to bug 61462.
       mParserContext->mRequest = 0;
     }
   }
 
   return result;
@@ -1569,17 +1567,19 @@ nsParser::SpeculativelyParse()
  * This method adds a new parser context to the list,
  * pushing the current one to the next position.
  *
  * @param   ptr to new context
  */
 void
 nsParser::PushContext(CParserContext& aContext)
 {
-  aContext.mPrevContext = mParserContext;
+  NS_ASSERTION(aContext.mPrevContext == mParserContext,
+               "Trying to push a context whose previous context differs from "
+               "the current parser context.");
   mParserContext = &aContext;
 }
 
 /**
  * This method pops the topmost context off the stack,
  * returning it to the user. The next context  (if any)
  * becomes the current context.
  * @update	gess7/22/98
@@ -1671,24 +1671,22 @@ nsParser::Terminate(void)
 
   // If we got interrupted in the middle of a document.write, then we might
   // have more than one parser context on our parsercontext stack. This has
   // the effect of making DidBuildModel a no-op, meaning that we never call
   // our sink's DidBuildModel and break the reference cycle, causing a leak.
   // Since we're getting terminated, we manually clean up our context stack.
   while (mParserContext && mParserContext->mPrevContext) {
     CParserContext *prev = mParserContext->mPrevContext;
-    NS_ASSERTION(prev->mPrevContext || prev->mDTD, "How is there no root DTD?");
-
     delete mParserContext;
     mParserContext = prev;
   }
 
-  if (mParserContext && mParserContext->mDTD) {
-    mParserContext->mDTD->Terminate();
+  if (mDTD) {
+    mDTD->Terminate();
     DidBuildModel(result);
   } else if (mSink) {
     // We have no parser context or no DTD yet (so we got terminated before we
     // got any data).  Manually break the reference cycle with the sink.
     result = mSink->DidBuildModel();
     NS_ENSURE_SUCCESS(result, result);
   }
 
@@ -1895,18 +1893,18 @@ nsParser::Parse(nsIURI* aURL,
     nsresult rv = aURL->GetSpec(spec);
     if (rv != NS_OK) {
       return rv;
     }
     NS_ConvertUTF8toUTF16 theName(spec);
 
     nsScanner* theScanner = new nsScanner(theName, PR_FALSE, mCharset,
                                           mCharsetSource);
-    CParserContext* pc = new CParserContext(theScanner, aKey, mCommand,
-                                            aListener);
+    CParserContext* pc = new CParserContext(mParserContext, theScanner, aKey,
+                                            mCommand, aListener);
     if (pc && theScanner) {
       pc->mMultipart = PR_TRUE;
       pc->mContextType = CParserContext::eCTURL;
       pc->mDTDMode = aMode;
       PushContext(*pc);
 
       // Here, and only here, hand this parser off to the scanner. We
       // only want to do that here since the only reason the scanner
@@ -1977,35 +1975,30 @@ nsParser::Parse(const nsAString& aSource
     }
 
     if (!pc) {
       // Only make a new context if we don't have one, OR if we do, but has a
       // different context key.
       nsScanner* theScanner = new nsScanner(mUnusedInput, mCharset, mCharsetSource);
       NS_ENSURE_TRUE(theScanner, NS_ERROR_OUT_OF_MEMORY);
 
-      nsIDTD *theDTD = nsnull;
       eAutoDetectResult theStatus = eUnknownDetect;
 
       if (mParserContext && mParserContext->mMimeType == aMimeType) {
         // Ref. Bug 90379
-        NS_ASSERTION(mParserContext->mDTD, "How come the DTD is null?");
+        NS_ASSERTION(mDTD, "How come the DTD is null?");
 
         if (mParserContext) {
-          // To fix bug 32263 we used create a new instance of the DTD!.
-          // All we need is a new tokenizer which now gets created with
-          // a parser context.
-          theDTD = mParserContext->mDTD;
           theStatus = mParserContext->mAutoDetectStatus;
           // Added this to fix bug 32022.
         }
       }
 
-      pc = new CParserContext(theScanner, aKey, mCommand,
-                              0, theDTD, theStatus, aLastCall);
+      pc = new CParserContext(mParserContext, theScanner, aKey, mCommand,
+                              0, theStatus, aLastCall);
       NS_ENSURE_TRUE(pc, NS_ERROR_OUT_OF_MEMORY);
 
       PushContext(*pc);
 
       pc->mMultipart = !aLastCall; // By default
       if (pc->mPrevContext) {
         pc->mMultipart |= pc->mPrevContext->mMultipart;
       }
@@ -2110,18 +2103,17 @@ nsParser::ParseFragment(const nsAString&
 
   if (!aXMLMode && theCount) {
     // First, we have to flush any tags that don't belong in the head if there
     // was no <body> in the context.
     // XXX This is extremely ugly. Maybe CNavDTD should have FlushMisplaced()?
     NS_ASSERTION(mParserContext, "Parsing didn't create a parser context?");
 
     CNavDTD* dtd = static_cast<CNavDTD*>
-                              (static_cast<nsIDTD*>
-                                          (mParserContext->mDTD));
+                              (static_cast<nsIDTD*>(mDTD));
     NS_ASSERTION(dtd, "How did we parse anything without a dtd?");
 
     CStartToken bodyToken(NS_LITERAL_STRING("BODY"), eHTMLTag_body);
     nsCParserNode bodyNode(&bodyToken, 0);
 
     dtd->OpenContainer(&bodyNode, eHTMLTag_body);
 
     // Now parse the flushed out tags.
@@ -2229,18 +2221,18 @@ nsParser::ResumeParse(PRBool allowIterat
                  "Bad races happening, expect to crash!");
 
     result = WillBuildModel(mParserContext->mScanner->GetFilename());
     if (NS_FAILED(result)) {
       mFlags &= ~NS_PARSER_FLAG_CAN_TOKENIZE;
       return result;
     }
 
-    if (mParserContext->mDTD) {
-      mParserContext->mDTD->WillResumeParse(mSink);
+    if (mDTD) {
+      mDTD->WillResumeParse(mSink);
       PRBool theIterationIsOk = PR_TRUE;
 
       while (result == NS_OK && theIterationIsOk) {
         if (!mUnusedInput.IsEmpty() && mParserContext->mScanner) {
           // -- Ref: Bug# 22485 --
           // Insert the unused input into the source buffer
           // as if it was read from the input stream.
           // Adding UngetReadable() per vidur!!
@@ -2267,18 +2259,18 @@ nsParser::ResumeParse(PRBool allowIterat
         // Make sure not to stop parsing too early. Therefore, before shutting
         // down the parser, it's important to check whether the input buffer
         // has been scanned to completion (theTokenizerResult should be kEOF).
         // kEOF -> End of buffer.
 
         // If we're told to block the parser, we disable all further parsing
         // (and cache any data coming in) until the parser is re-enabled.
         if (NS_ERROR_HTMLPARSER_BLOCK == result) {
-          if (mParserContext->mDTD) {
-            mParserContext->mDTD->WillInterruptParse(mSink);
+          if (mDTD) {
+            mDTD->WillInterruptParse(mSink);
           }
 
           if (mFlags & NS_PARSER_FLAG_PARSER_ENABLED) {
             // If we were blocked by a recursive invocation, don't re-block.
             BlockParser();
             SpeculativelyParse();
           }
           return NS_OK;
@@ -2334,18 +2326,18 @@ nsParser::ResumeParse(PRBool allowIterat
               // ...then intentionally fall through to WillInterruptParse()...
             }
           }
         }
 
         if (theTokenizerResult == kEOF ||
             result == NS_ERROR_HTMLPARSER_INTERRUPTED) {
           result = (result == NS_ERROR_HTMLPARSER_INTERRUPTED) ? NS_OK : result;
-          if (mParserContext->mDTD) {
-            mParserContext->mDTD->WillInterruptParse(mSink);
+          if (mDTD) {
+            mDTD->WillInterruptParse(mSink);
           }
         }
       }
     } else {
       mInternalState = result = NS_ERROR_HTMLPARSER_UNRESOLVEDDTD;
     }
   }
 
@@ -2357,36 +2349,27 @@ nsParser::ResumeParse(PRBool allowIterat
 
 /**
  *  This is where we loop over the tokens created in the
  *  tokenization phase, and try to make sense out of them.
  */
 nsresult
 nsParser::BuildModel()
 {
-  CParserContext* theRootContext = mParserContext;
-  nsITokenizer*   theTokenizer = nsnull;
+  nsITokenizer* theTokenizer = nsnull;
 
   nsresult result = NS_OK;
   if (mParserContext) {
-    PRInt32 type = mParserContext->mDTD ? mParserContext->mDTD->GetType() :
-                                          NS_IPARSER_FLAG_HTML;
-    result = mParserContext->GetTokenizer(type, mSink, theTokenizer);
+    result = mParserContext->GetTokenizer(mDTD, mSink, theTokenizer);
   }
 
   if (NS_SUCCEEDED(result)) {
-    // Get the root DTD for use in model building...
-    while (theRootContext->mPrevContext) {
-      theRootContext = theRootContext->mPrevContext;
-    }
-
-    nsIDTD* theRootDTD = theRootContext->mDTD;
-    if (theRootDTD) {
+    if (mDTD) {
       MOZ_TIMER_START(mDTDTime);
-      result = theRootDTD->BuildModel(this, theTokenizer, nsnull, mSink);
+      result = mDTD->BuildModel(this, theTokenizer, nsnull, mSink);
       MOZ_TIMER_STOP(mDTDTime);
     }
   } else {
     mInternalState = result = NS_ERROR_HTMLPARSER_BADTOKENIZER;
   }
   return result;
 }
 
@@ -2400,19 +2383,22 @@ nsParser::OnStartRequest(nsIRequest *req
   NS_PRECONDITION(eNone == mParserContext->mStreamListenerState,
                   "Parser's nsIStreamListener API was not setup "
                   "correctly in constructor.");
   if (mObserver) {
     mObserver->OnStartRequest(request, aContext);
   }
   mParserContext->mStreamListenerState = eOnStart;
   mParserContext->mAutoDetectStatus = eUnknownDetect;
-  mParserContext->mDTD = nsnull;
   mParserContext->mRequest = request;
 
+  NS_ASSERTION(!mParserContext->mPrevContext,
+               "Clobbering DTD for non-root parser context!");
+  mDTD = nsnull;
+
   nsresult rv;
   nsCAutoString contentType;
   nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
   if (channel) {
     rv = channel->GetContentType(contentType);
     if (NS_SUCCEEDED(rv)) {
       mParserContext->SetMimeType(contentType);
     }
@@ -2990,19 +2976,17 @@ nsParser::OnStopRequest(nsIRequest *requ
 PRBool
 nsParser::WillTokenize(PRBool aIsFinalChunk)
 {
   if (!mParserContext) {
     return PR_TRUE;
   }
 
   nsITokenizer* theTokenizer;
-  PRInt32 type = mParserContext->mDTD ? mParserContext->mDTD->GetType() :
-                                        NS_IPARSER_FLAG_HTML;
-  nsresult result = mParserContext->GetTokenizer(type, mSink, theTokenizer);
+  nsresult result = mParserContext->GetTokenizer(mDTD, mSink, theTokenizer);
   NS_ENSURE_SUCCESS(result, PR_FALSE);
   return NS_SUCCEEDED(theTokenizer->WillTokenize(aIsFinalChunk,
                                                  &mTokenAllocator));
 }
 
 
 /**
  * This is the primary control routine to consume tokens.
@@ -3010,19 +2994,17 @@ nsParser::WillTokenize(PRBool aIsFinalCh
  * you run out of data.
  */
 nsresult nsParser::Tokenize(PRBool aIsFinalChunk)
 {
   nsITokenizer* theTokenizer;
 
   nsresult result = NS_ERROR_NOT_AVAILABLE;
   if (mParserContext) {
-    PRInt32 type = mParserContext->mDTD ? mParserContext->mDTD->GetType()
-                                        : NS_IPARSER_FLAG_HTML;
-    result = mParserContext->GetTokenizer(type, mSink, theTokenizer);
+    result = mParserContext->GetTokenizer(mDTD, mSink, theTokenizer);
   }
 
   if (NS_SUCCEEDED(result)) {
     if (mFlags & NS_PARSER_FLAG_FLUSH_TOKENS) {
       // For some reason tokens didn't get flushed (probably
       // the parser got blocked before all the tokens in the
       // stack got handled). Flush 'em now. Ref. bug 104856
       if (theTokenizer->GetCount() != 0) {
@@ -3087,19 +3069,17 @@ nsresult nsParser::Tokenize(PRBool aIsFi
 PRBool
 nsParser::DidTokenize(PRBool aIsFinalChunk)
 {
   if (!mParserContext) {
     return PR_TRUE;
   }
 
   nsITokenizer* theTokenizer;
-  PRInt32 type = mParserContext->mDTD ? mParserContext->mDTD->GetType() :
-                                        NS_IPARSER_FLAG_HTML;
-  nsresult rv = mParserContext->GetTokenizer(type, mSink, theTokenizer);
+  nsresult rv = mParserContext->GetTokenizer(mDTD, mSink, theTokenizer);
   NS_ENSURE_SUCCESS(rv, PR_FALSE);
 
   rv = theTokenizer->DidTokenize(aIsFinalChunk);
   return NS_SUCCEEDED(rv);
 }
 
 /**
  * Get the channel associated with this parser
@@ -3119,14 +3099,14 @@ nsParser::GetChannel(nsIChannel** aChann
 
 /**
  * Get the DTD associated with this parser
  */
 NS_IMETHODIMP
 nsParser::GetDTD(nsIDTD** aDTD)
 {
   if (mParserContext) {
-    NS_IF_ADDREF(*aDTD = mParserContext->mDTD);
+    NS_IF_ADDREF(*aDTD = mDTD);
   }
 
   return NS_OK;
 }
 
--- a/parser/htmlparser/src/nsParser.h
+++ b/parser/htmlparser/src/nsParser.h
@@ -466,16 +466,17 @@ private:
 
 protected:
     //*********************************************
     // And now, some data members...
     //*********************************************
     
       
     CParserContext*              mParserContext;
+    nsCOMPtr<nsIDTD>             mDTD;
     nsCOMPtr<nsIRequestObserver> mObserver;
     nsCOMPtr<nsIContentSink>     mSink;
     nsIRunnable*                 mContinueEvent;  // weak ref
     nsRefPtr<nsSpeculativeScriptThread> mSpeculativeScriptThread;
    
     nsCOMPtr<nsIParserFilter> mParserFilter;
     nsTokenAllocator          mTokenAllocator;