Bug 714777 - Refactor fragment parsing out of nsHtml5Parser. r=smaug.
authorHenri Sivonen <hsivonen@iki.fi>
Fri, 20 Jan 2012 13:16:27 +0200
changeset 87806 69a75d09b8c133c13f3eed393dce4697b6f998ee
parent 87805 3d760b97157b818dfb5be521915e5c20cf665fb7
child 87807 8bb4941a7f7de6b6a6ef87d393a4367c38bafe7c
push id129
push userffxbld
push dateFri, 20 Apr 2012 19:40:49 +0000
treeherdermozilla-release@5bcfa0da3be9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs714777
milestone12.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 714777 - Refactor fragment parsing out of nsHtml5Parser. r=smaug.
content/base/public/nsContentUtils.h
content/base/src/mozSanitizingSerializer.h
content/base/src/nsContentSink.cpp
content/base/src/nsContentSink.h
content/base/src/nsContentUtils.cpp
content/base/src/nsPlainTextSerializer.h
content/html/document/src/nsHTMLContentSink.cpp
content/xml/document/src/nsXMLContentSink.cpp
content/xml/document/src/nsXMLContentSink.h
content/xml/document/src/nsXMLFragmentContentSink.cpp
content/xslt/src/xslt/txMozillaStylesheetCompiler.cpp
content/xul/document/src/nsXULContentSink.cpp
content/xul/document/src/nsXULContentSink.h
parser/html/Makefile.in
parser/html/nsHtml5Parser.cpp
parser/html/nsHtml5Parser.h
parser/html/nsHtml5StringParser.cpp
parser/html/nsHtml5StringParser.h
parser/html/nsHtml5TreeOpExecutor.cpp
parser/html/nsHtml5TreeOpExecutor.h
parser/htmlparser/public/Makefile.in
parser/htmlparser/public/nsIContentSink.h
parser/htmlparser/public/nsIDTD.h
parser/htmlparser/public/nsIParser.h
parser/htmlparser/public/nsParserBase.h
parser/htmlparser/src/CNavDTD.cpp
parser/htmlparser/src/nsExpatDriver.cpp
parser/htmlparser/src/nsLoggingSink.cpp
parser/htmlparser/src/nsLoggingSink.h
parser/htmlparser/src/nsParser.cpp
parser/htmlparser/src/nsParser.h
parser/xml/src/nsSAXXMLReader.cpp
parser/xml/src/nsSAXXMLReader.h
rdf/base/src/nsRDFContentSink.cpp
toolkit/components/places/nsPlacesImportExportService.cpp
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -74,19 +74,24 @@ static fp_except_t oldmask = fpsetmask(~
 #include "nsIScriptGlobalObject.h"
 #include "nsIDOMEvent.h"
 #include "nsTArray.h"
 #include "nsTextFragment.h"
 #include "nsReadableUtils.h"
 #include "nsINode.h"
 #include "nsHashtable.h"
 #include "nsIDOMNode.h"
-#include "nsHtml5Parser.h"
+#include "nsHtml5StringParser.h"
+#include "nsIParser.h"
+#include "nsIDocument.h"
 #include "nsIFragmentContentSink.h"
+#include "nsContentSink.h"
 #include "nsMathUtils.h"
+#include "nsThreadUtils.h"
+#include "nsIContent.h"
 #include "nsCharSeparatedTokenizer.h"
 
 #include "mozilla/AutoRestore.h"
 #include "mozilla/GuardObjects.h"
 #include "mozilla/TimeStamp.h"
 
 struct nsNativeKeyEvent; // Don't include nsINativeKeyBindings.h here: it will force strange compilation error!
 
@@ -1934,17 +1939,17 @@ private:
 
   static bool sIsHandlingKeyBoardEvent;
   static bool sAllowXULXBL_for_file;
   static bool sIsFullScreenApiEnabled;
   static bool sTrustedFullScreenOnly;
   static bool sFullScreenKeyInputRestricted;
   static PRUint32 sHandlingInputTimeout;
 
-  static nsHtml5Parser* sHTMLFragmentParser;
+  static nsHtml5StringParser* sHTMLFragmentParser;
   static nsIParser* sXMLFragmentParser;
   static nsIFragmentContentSink* sXMLFragmentSink;
 
   /**
    * True if there's a fragment parser activation on the stack.
    */
   static bool sFragmentParsingActive;
 
--- a/content/base/src/mozSanitizingSerializer.h
+++ b/content/base/src/mozSanitizingSerializer.h
@@ -98,17 +98,17 @@ public:
 
   NS_IMETHOD AppendDocumentStart(nsIDocument *aDocument,
                                  nsAString& aStr);
 
   // nsIContentSink
   NS_IMETHOD WillParse(void) { return NS_OK; }
   NS_IMETHOD WillInterrupt(void) { return NS_OK; }
   NS_IMETHOD WillResume(void) { return NS_OK; }
-  NS_IMETHOD SetParser(nsIParser* aParser) { return NS_OK; }
+  NS_IMETHOD SetParser(nsParserBase* aParser) { return NS_OK; }
   NS_IMETHOD OpenContainer(const nsIParserNode& aNode);
   NS_IMETHOD CloseContainer(const nsHTMLTag aTag);
   NS_IMETHOD AddLeaf(const nsIParserNode& aNode);
   NS_IMETHOD AddComment(const nsIParserNode& aNode) { return NS_OK; }
   NS_IMETHOD AddProcessingInstruction(const nsIParserNode& aNode)
                                                     { return NS_OK; }
   NS_IMETHOD AddDocTypeDecl(const nsIParserNode& aNode);
   virtual void FlushPendingNotifications(mozFlushType aType) { }
--- a/content/base/src/nsContentSink.cpp
+++ b/content/base/src/nsContentSink.cpp
@@ -1349,17 +1349,17 @@ nsContentSink::WillResumeImpl()
   mParsing = true;
 
   return NS_OK;
 }
 
 nsresult
 nsContentSink::DidProcessATokenImpl()
 {
-  if (!mCanInterruptParser || !mParser || !mParser->CanInterrupt()) {
+  if (!mCanInterruptParser || !mParser) {
     return NS_OK;
   }
 
   // Get the current user event time
   nsIPresShell *shell = mDocument->GetShell();
   if (!shell) {
     // If there's no pres shell in the document, return early since
     // we're not laying anything out here.
@@ -1478,17 +1478,17 @@ nsContentSink::DropParserAndPerfHint(voi
   
   // Ref. Bug 49115
   // Do this hack to make sure that the parser
   // doesn't get destroyed, accidently, before
   // the circularity, between sink & parser, is
   // actually broken.
   // Drop our reference to the parser to get rid of a circular
   // reference.
-  nsCOMPtr<nsIParser> kungFuDeathGrip(mParser.forget());
+  nsRefPtr<nsParserBase> kungFuDeathGrip(mParser.forget());
 
   if (mDynamicLowerValue) {
     // Reset the performance hint which was set to FALSE
     // when mDynamicLowerValue was set.
     FavorPerformanceHint(true, 0);
   }
 
   if (mCanInterruptParser) {
--- a/content/base/src/nsContentSink.h
+++ b/content/base/src/nsContentSink.h
@@ -302,17 +302,17 @@ protected:
 private:
   // People shouldn't be allocating this class directly.  All subclasses should
   // be allocated using a zeroing operator new.
   void* operator new(size_t sz) CPP_THROW_NEW;  // Not to be implemented
 
 protected:
 
   nsCOMPtr<nsIDocument>         mDocument;
-  nsCOMPtr<nsIParser>           mParser;
+  nsRefPtr<nsParserBase>        mParser;
   nsCOMPtr<nsIURI>              mDocumentURI;
   nsCOMPtr<nsIDocShell>         mDocShell;
   nsRefPtr<mozilla::css::Loader> mCSSLoader;
   nsRefPtr<nsNodeInfoManager>   mNodeInfoManager;
   nsRefPtr<nsScriptLoader>      mScriptLoader;
 
   // back off timer notification after count
   PRInt32 mBackoffCount;
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -274,17 +274,17 @@ nsString* nsContentUtils::sModifierSepar
 
 bool nsContentUtils::sInitialized = false;
 bool nsContentUtils::sIsFullScreenApiEnabled = false;
 bool nsContentUtils::sTrustedFullScreenOnly = true;
 bool nsContentUtils::sFullScreenKeyInputRestricted = true;
 
 PRUint32 nsContentUtils::sHandlingInputTimeout = 1000;
 
-nsHtml5Parser* nsContentUtils::sHTMLFragmentParser = nsnull;
+nsHtml5StringParser* nsContentUtils::sHTMLFragmentParser = nsnull;
 nsIParser* nsContentUtils::sXMLFragmentParser = nsnull;
 nsIFragmentContentSink* nsContentUtils::sXMLFragmentSink = nsnull;
 bool nsContentUtils::sFragmentParsingActive = false;
 
 static PLDHashTable sEventListenerManagersHash;
 
 class EventListenerManagerMapEntry : public PLDHashEntryHdr
 {
@@ -3658,28 +3658,26 @@ nsContentUtils::ParseFragmentHTML(const 
 {
   if (nsContentUtils::sFragmentParsingActive) {
     NS_NOTREACHED("Re-entrant fragment parsing attempted.");
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
   mozilla::AutoRestore<bool> guard(nsContentUtils::sFragmentParsingActive);
   nsContentUtils::sFragmentParsingActive = true;
   if (!sHTMLFragmentParser) {
-    sHTMLFragmentParser =
-      static_cast<nsHtml5Parser*>(nsHtml5Module::NewHtml5Parser().get());
+    NS_ADDREF(sHTMLFragmentParser = new nsHtml5StringParser());
     // Now sHTMLFragmentParser owns the object
   }
   nsresult rv =
     sHTMLFragmentParser->ParseHtml5Fragment(aSourceBuffer,
                                             aTargetNode,
                                             aContextLocalName,
                                             aContextNamespace,
                                             aQuirks,
                                             aPreventScriptExecution);
-  sHTMLFragmentParser->Reset();
   return rv;
 }
 
 /* static */
 nsresult
 nsContentUtils::ParseFragmentXML(const nsAString& aSourceBuffer,
                                  nsIDocument* aDocument,
                                  nsTArray<nsString>& aTagStack,
--- a/content/base/src/nsPlainTextSerializer.h
+++ b/content/base/src/nsPlainTextSerializer.h
@@ -99,17 +99,17 @@ public:
 
   NS_IMETHOD AppendDocumentStart(nsIDocument *aDocument,
                                  nsAString& aStr);
 
   // nsIContentSink
   NS_IMETHOD WillParse(void) { return NS_OK; }
   NS_IMETHOD WillInterrupt(void) { return NS_OK; }
   NS_IMETHOD WillResume(void) { return NS_OK; }
-  NS_IMETHOD SetParser(nsIParser* aParser) { return NS_OK; }
+  NS_IMETHOD SetParser(nsParserBase* aParser) { return NS_OK; }
   NS_IMETHOD OpenContainer(const nsIParserNode& aNode);
   NS_IMETHOD CloseContainer(const nsHTMLTag aTag);
   NS_IMETHOD AddLeaf(const nsIParserNode& aNode);
   NS_IMETHOD AddComment(const nsIParserNode& aNode) { return NS_OK; }
   NS_IMETHOD AddProcessingInstruction(const nsIParserNode& aNode) { return NS_OK; }
   NS_IMETHOD AddDocTypeDecl(const nsIParserNode& aNode) { return NS_OK; }
   virtual void FlushPendingNotifications(mozFlushType aType) { }
   NS_IMETHOD SetDocumentCharset(nsACString& aCharset) { return NS_OK; }
--- a/content/html/document/src/nsHTMLContentSink.cpp
+++ b/content/html/document/src/nsHTMLContentSink.cpp
@@ -186,17 +186,17 @@ public:
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLContentSink, nsContentSink)
 
   // nsIContentSink
   NS_IMETHOD WillParse(void);
   NS_IMETHOD WillBuildModel(nsDTDMode aDTDMode);
   NS_IMETHOD DidBuildModel(bool aTerminated);
   NS_IMETHOD WillInterrupt(void);
   NS_IMETHOD WillResume(void);
-  NS_IMETHOD SetParser(nsIParser* aParser);
+  NS_IMETHOD SetParser(nsParserBase* aParser);
   virtual void FlushPendingNotifications(mozFlushType aType);
   NS_IMETHOD SetDocumentCharset(nsACString& aCharset);
   virtual nsISupports *GetTarget();
   virtual bool IsScriptExecuting();
 
   // nsIHTMLContentSink
   NS_IMETHOD OpenContainer(const nsIParserNode& aNode);
   NS_IMETHOD CloseContainer(const nsHTMLTag aTag);
@@ -1711,17 +1711,17 @@ HTMLContentSink::DidBuildModel(bool aTer
   mDocument->EndLoad();
 
   DropParserAndPerfHint();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-HTMLContentSink::SetParser(nsIParser* aParser)
+HTMLContentSink::SetParser(nsParserBase* aParser)
 {
   NS_PRECONDITION(aParser, "Should have a parser here!");
   mParser = aParser;
   return NS_OK;
 }
 
 NS_IMETHODIMP_(bool)
 HTMLContentSink::IsFormOnStack()
--- a/content/xml/document/src/nsXMLContentSink.cpp
+++ b/content/xml/document/src/nsXMLContentSink.cpp
@@ -202,17 +202,17 @@ nsXMLContentSink::WillBuildModel(nsDTDMo
   WillBuildModelImpl();
 
   // Notify document that the load is beginning
   mDocument->BeginLoad();
 
   // Check for correct load-command for maybe prettyprinting
   if (mPrettyPrintXML) {
     nsCAutoString command;
-    mParser->GetCommand(command);
+    GetParser()->GetCommand(command);
     if (!command.EqualsLiteral("view")) {
       mPrettyPrintXML = false;
     }
   }
   
   return NS_OK;
 }
 
@@ -468,17 +468,17 @@ nsXMLContentSink::WillInterrupt(void)
 
 NS_IMETHODIMP
 nsXMLContentSink::WillResume(void)
 {
   return WillResumeImpl();
 }
 
 NS_IMETHODIMP
-nsXMLContentSink::SetParser(nsIParser* aParser)
+nsXMLContentSink::SetParser(nsParserBase* aParser)
 {
   NS_PRECONDITION(aParser, "Should have a parser here!");
   mParser = aParser;
   return NS_OK;
 }
 
 nsresult
 nsXMLContentSink::CreateElement(const PRUnichar** aAtts, PRUint32 aAttsCount,
@@ -497,17 +497,17 @@ nsXMLContentSink::CreateElement(const PR
   rv = NS_NewElement(getter_AddRefs(content), ni.forget(), aFromParser);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML)
       || aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG)
     ) {
     nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(content);
     sele->SetScriptLineNumber(aLineNumber);
-    sele->SetCreatorParser(mParser);
+    sele->SetCreatorParser(GetParser());
     mConstrainSize = false;
   }
 
   // XHTML needs some special attention
   if (aNodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) {
     mPrettyPrintHasFactoredElements = true;
   }
   else {
@@ -599,17 +599,17 @@ nsXMLContentSink::CloseElement(nsIConten
     // Now tell the script that it's ready to go. This may execute the script
     // or return true, or neither if the script doesn't need executing.
     bool block = sele->AttemptToExecute();
 
     // If the parser got blocked, make sure to return the appropriate rv.
     // I'm not sure if this is actually needed or not.
     if (mParser && !mParser->IsParserEnabled()) {
       // XXX The HTML sink doesn't call BlockParser here, why do we?
-      mParser->BlockParser();
+      GetParser()->BlockParser();
       block = true;
     }
 
     return block ? NS_ERROR_HTMLPARSER_BLOCK : NS_OK;
   }
   
   nsresult rv = NS_OK;
   if (nodeInfo->Equals(nsGkAtoms::meta, kNameSpaceID_XHTML) &&
@@ -722,17 +722,17 @@ nsXMLContentSink::ProcessStyleLink(nsICo
                                    const nsSubstring& aType,
                                    const nsSubstring& aMedia)
 {
   nsresult rv = NS_OK;
   mPrettyPrintXML = false;
 
   nsCAutoString cmd;
   if (mParser)
-    mParser->GetCommand(cmd);
+    GetParser()->GetCommand(cmd);
   if (cmd.EqualsASCII(kLoadAsData))
     return NS_OK; // Do not load stylesheets when loading as data
 
   NS_ConvertUTF16toUTF8 type(aType);
   if (type.EqualsIgnoreCase(TEXT_XSL) ||
       type.EqualsIgnoreCase(APPLICATION_XSLT_XML) ||
       type.EqualsIgnoreCase(TEXT_XML) ||
       type.EqualsIgnoreCase(APPLICATION_XML)) {
@@ -1675,21 +1675,26 @@ nsXMLContentSink::IsMonolithicContainer(
           (aNodeInfo->NameAtom() == nsGkAtoms::math))
           );
 }
 
 void
 nsXMLContentSink::ContinueInterruptedParsingIfEnabled()
 {
   if (mParser && mParser->IsParserEnabled()) {
-    mParser->ContinueInterruptedParsing();
+    GetParser()->ContinueInterruptedParsing();
   }
 }
 
 void
 nsXMLContentSink::ContinueInterruptedParsingAsync()
 {
   nsCOMPtr<nsIRunnable> ev = NS_NewRunnableMethod(this,
     &nsXMLContentSink::ContinueInterruptedParsingIfEnabled);
 
   NS_DispatchToCurrentThread(ev);
 }
 
+nsIParser*
+nsXMLContentSink::GetParser()
+{
+  return static_cast<nsIParser*>(mParser.get());
+}
--- a/content/xml/document/src/nsXMLContentSink.h
+++ b/content/xml/document/src/nsXMLContentSink.h
@@ -92,17 +92,17 @@ public:
   NS_DECL_NSIEXPATSINK
 
   // nsIContentSink
   NS_IMETHOD WillParse(void);
   NS_IMETHOD WillBuildModel(nsDTDMode aDTDMode);
   NS_IMETHOD DidBuildModel(bool aTerminated);
   NS_IMETHOD WillInterrupt(void);
   NS_IMETHOD WillResume(void);
-  NS_IMETHOD SetParser(nsIParser* aParser);  
+  NS_IMETHOD SetParser(nsParserBase* aParser);
   virtual void FlushPendingNotifications(mozFlushType aType);
   NS_IMETHOD SetDocumentCharset(nsACString& aCharset);
   virtual nsISupports *GetTarget();
   virtual bool IsScriptExecuting();
   virtual void ContinueInterruptedParsingAsync();
 
   // nsITransformObserver
   NS_IMETHOD OnDocumentCreated(nsIDocument *aResultDocument);
@@ -112,16 +112,18 @@ public:
   NS_IMETHOD StyleSheetLoaded(nsCSSStyleSheet* aSheet, bool aWasAlternate,
                               nsresult aStatus);
   static bool ParsePIData(const nsString &aData, nsString &aHref,
                           nsString &aTitle, nsString &aMedia,
                           bool &aIsAlternate);
 
 protected:
 
+  nsIParser* GetParser();
+
   void ContinueInterruptedParsingIfEnabled();
 
   // Start layout.  If aIgnorePendingSheets is true, this will happen even if
   // we still have stylesheet loads pending.  Otherwise, we'll wait until the
   // stylesheets are all done loading.
   virtual void MaybeStartLayout(bool aIgnorePendingSheets);
 
   virtual nsresult AddAttributes(const PRUnichar** aNode, nsIContent* aContent);
--- a/content/xml/document/src/nsXMLFragmentContentSink.cpp
+++ b/content/xml/document/src/nsXMLFragmentContentSink.cpp
@@ -206,17 +206,17 @@ nsXMLFragmentContentSink::WillBuildModel
   mRoot = do_QueryInterface(frag);
   
   return rv;
 }
 
 NS_IMETHODIMP 
 nsXMLFragmentContentSink::DidBuildModel(bool aTerminated)
 {
-  nsCOMPtr<nsIParser> kungFuDeathGrip(mParser);
+  nsRefPtr<nsParserBase> kungFuDeathGrip(mParser);
 
   // Drop our reference to the parser to get rid of a circular
   // reference.
   mParser = nsnull;
 
   return NS_OK;
 }
 
--- a/content/xslt/src/xslt/txMozillaStylesheetCompiler.cpp
+++ b/content/xslt/src/xslt/txMozillaStylesheetCompiler.cpp
@@ -110,17 +110,17 @@ public:
     NS_DECL_NSIREQUESTOBSERVER
     NS_DECL_NSIINTERFACEREQUESTOR
 
     // nsIContentSink
     NS_IMETHOD WillParse(void) { return NS_OK; }
     NS_IMETHOD DidBuildModel(bool aTerminated);
     NS_IMETHOD WillInterrupt(void) { return NS_OK; }
     NS_IMETHOD WillResume(void) { return NS_OK; }
-    NS_IMETHOD SetParser(nsIParser* aParser) { return NS_OK; }
+    NS_IMETHOD SetParser(nsParserBase* aParser) { return NS_OK; }
     virtual void FlushPendingNotifications(mozFlushType aType) { }
     NS_IMETHOD SetDocumentCharset(nsACString& aCharset) { return NS_OK; }
     virtual nsISupports *GetTarget() { return nsnull; }
 
 private:
     nsRefPtr<txStylesheetCompiler> mCompiler;
     nsCOMPtr<nsIStreamListener> mListener;
     bool mCheckedForXML;
--- a/content/xul/document/src/nsXULContentSink.cpp
+++ b/content/xul/document/src/nsXULContentSink.cpp
@@ -295,17 +295,17 @@ XULContentSinkImpl::WillInterrupt(void)
 NS_IMETHODIMP 
 XULContentSinkImpl::WillResume(void)
 {
     // XXX Notify the docshell, if necessary
     return NS_OK;
 }
 
 NS_IMETHODIMP 
-XULContentSinkImpl::SetParser(nsIParser* aParser)
+XULContentSinkImpl::SetParser(nsParserBase* aParser)
 {
     NS_IF_RELEASE(mParser);
     mParser = aParser;
     NS_IF_ADDREF(mParser);
     return NS_OK;
 }
 
 NS_IMETHODIMP 
--- a/content/xul/document/src/nsXULContentSink.h
+++ b/content/xul/document/src/nsXULContentSink.h
@@ -69,17 +69,17 @@ public:
     NS_DECL_NSIEXPATSINK
 
     // nsIContentSink
     NS_IMETHOD WillParse(void) { return NS_OK; }
     NS_IMETHOD WillBuildModel(nsDTDMode aDTDMode);
     NS_IMETHOD DidBuildModel(bool aTerminated);
     NS_IMETHOD WillInterrupt(void);
     NS_IMETHOD WillResume(void);
-    NS_IMETHOD SetParser(nsIParser* aParser);
+    NS_IMETHOD SetParser(nsParserBase* aParser);
     virtual void FlushPendingNotifications(mozFlushType aType) { }
     NS_IMETHOD SetDocumentCharset(nsACString& aCharset);
     virtual nsISupports *GetTarget();
 
     /**
      * Initialize the content sink, giving it an nsIDocument object
      * with which to communicate with the outside world, and an
      * nsXULPrototypeDocument to build.
@@ -175,13 +175,13 @@ protected:
     ContextStack mContextStack;
 
     nsWeakPtr              mDocument;             // [OWNER]
     nsCOMPtr<nsIURI>       mDocumentURL;          // [OWNER]
 
     nsRefPtr<nsXULPrototypeDocument> mPrototype;  // [OWNER]
 
     // We use regular pointer b/c of funky exports on nsIParser:
-    nsIParser*             mParser;               // [OWNER]
+    nsParserBase*         mParser;               // [OWNER]
     nsCOMPtr<nsIScriptSecurityManager> mSecMan;
 };
 
 #endif /* nsXULContentSink_h__ */
--- a/parser/html/Makefile.in
+++ b/parser/html/Makefile.in
@@ -72,16 +72,17 @@ EXPORTS		= \
 		nsHtml5TreeOpExecutor.h \
 		nsAHtml5TreeOpSink.h \
 		nsHtml5TreeOpStage.h \
 		nsHtml5UTF16Buffer.h \
 		nsHtml5UTF16BufferHSupplement.h \
 		nsHtml5DependentUTF16Buffer.h \
 		nsHtml5OwningUTF16Buffer.h \
 		nsHtml5ViewSourceUtils.h \
+		nsHtml5StringParser.h \
 		$(NULL)
 
 CPPSRCS		= \
 		nsHtml5Atoms.cpp \
 		nsHtml5Atom.cpp \
 		nsHtml5AtomTable.cpp \
 		nsHtml5Parser.cpp \
 		nsHtml5AttributeName.cpp \
@@ -105,16 +106,17 @@ CPPSRCS		= \
 		nsHtml5StateSnapshot.cpp \
 		nsHtml5TreeOpExecutor.cpp \
 		nsHtml5StreamParser.cpp \
 		nsHtml5Speculation.cpp \
 		nsHtml5SpeculativeLoad.cpp \
 		nsHtml5SVGLoadDispatcher.cpp \
 		nsHtml5Highlighter.cpp \
 		nsHtml5ViewSourceUtils.cpp \
+		nsHtml5StringParser.cpp \
 		$(NULL)
 
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/rules.mk
 
 INCLUDES	+= \
 		-I$(srcdir)/../../content/base/src \
--- a/parser/html/nsHtml5Parser.cpp
+++ b/parser/html/nsHtml5Parser.cpp
@@ -560,89 +560,16 @@ nsHtml5Parser::Terminate()
 
 NS_IMETHODIMP
 nsHtml5Parser::ParseFragment(const nsAString& aSourceBuffer,
                              nsTArray<nsString>& aTagStack)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
-nsresult
-nsHtml5Parser::ParseHtml5Fragment(const nsAString& aSourceBuffer,
-                                  nsIContent* aTargetNode,
-                                  nsIAtom* aContextLocalName,
-                                  PRInt32 aContextNamespace,
-                                  bool aQuirks,
-                                  bool aPreventScriptExecution)
-{
-  NS_ENSURE_TRUE(aSourceBuffer.Length() <= PR_INT32_MAX,
-      NS_ERROR_OUT_OF_MEMORY);
-  nsIDocument* doc = aTargetNode->OwnerDoc();
-  
-  nsIURI* uri = doc->GetDocumentURI();
-  NS_ENSURE_TRUE(uri, NS_ERROR_NOT_AVAILABLE);
-
-  mExecutor->EnableFragmentMode(aPreventScriptExecution);
-
-  Initialize(doc, uri, nsnull, nsnull);
-
-  mExecutor->SetParser(this);
-  mExecutor->SetNodeInfoManager(doc->NodeInfoManager());
-
-  nsIContent* target = aTargetNode;
-  mTreeBuilder->setFragmentContext(aContextLocalName,
-                                   aContextNamespace,
-                                   &target,
-                                   aQuirks);
-
-#ifdef DEBUG
-  if (!aPreventScriptExecution) {
-    NS_ASSERTION(!aTargetNode->IsInDoc(),
-        "If script execution isn't prevented, "
-        "the target node must not be in doc.");
-    nsCOMPtr<nsIDOMDocumentFragment> domFrag = do_QueryInterface(aTargetNode);
-    NS_ASSERTION(domFrag,
-        "If script execution isn't prevented, must parse to DOM fragment.");
-  }
-#endif
-
-  NS_PRECONDITION(!mExecutor->HasStarted(),
-                  "Tried to start parse without initializing the parser.");
-  mTreeBuilder->setScriptingEnabled(mExecutor->IsScriptEnabled());
-  mTokenizer->start();
-  mExecutor->Start(); // Don't call WillBuildModel in fragment case
-  if (!aSourceBuffer.IsEmpty()) {
-    bool lastWasCR = false;
-    nsHtml5DependentUTF16Buffer buffer(aSourceBuffer);    
-    while (buffer.hasMore()) {
-      buffer.adjust(lastWasCR);
-      lastWasCR = false;
-      if (buffer.hasMore()) {
-        lastWasCR = mTokenizer->tokenizeBuffer(&buffer);
-        if (mTreeBuilder->HasScript()) {
-          // Flush on each script, because the execution prevention code
-          // can handle at most one script per flush.
-          mTreeBuilder->Flush(); // Move ops to the executor
-          mExecutor->FlushDocumentWrite(); // run the ops
-        }
-      }
-    }
-  }
-  mTokenizer->eof();
-  mTreeBuilder->StreamEnded();
-  mTreeBuilder->Flush();
-  mExecutor->FlushDocumentWrite();
-  mTokenizer->end();
-  mExecutor->DropParserAndPerfHint();
-  mExecutor->DropHeldElements();
-  mTreeBuilder->DropHandles();
-  mAtomTable.Clear();
-  return NS_OK;
-}
-
 NS_IMETHODIMP
 nsHtml5Parser::BuildModel()
 {
   NS_NOTREACHED("Don't call this!");
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
@@ -650,31 +577,17 @@ nsHtml5Parser::CancelParsingEvents()
 {
   NS_NOTREACHED("Don't call this!");
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 void
 nsHtml5Parser::Reset()
 {
-  NS_PRECONDITION(mExecutor->IsFragmentMode(),
-                  "Reset called on a non-fragment parser.");
-  mExecutor->Reset();
-  mLastWasCR = false;
-  UnblockParser();
-  mDocumentClosed = false;
-  mStreamParser = nsnull;
-  mRootContextLineNumber = 1;
-  mParserInsertedScriptsBeingEvaluated = 0;
-  mAtomTable.Clear(); // should be already cleared in the fragment case anyway
-  // Portable parser objects
-  mFirstBuffer->next = nsnull;
-  mFirstBuffer->setStart(0);
-  mFirstBuffer->setEnd(0);
-  mLastBuffer = mFirstBuffer;
+  NS_NOTREACHED("Don't call this!");
 }
 
 bool
 nsHtml5Parser::CanInterrupt()
 {
   // nsContentSink needs this to let nsContentSink::DidProcessATokenImpl
   // interrupt.
   return true;
--- a/parser/html/nsHtml5Parser.h
+++ b/parser/html/nsHtml5Parser.h
@@ -208,17 +208,17 @@ class nsHtml5Parser : public nsIParser,
     NS_IMETHOD BuildModel();
 
     /**
      * Don't call. For interface compat only.
      */
     NS_IMETHODIMP CancelParsingEvents();
 
     /**
-     * Sets the state to initial values
+     * Don't call. For interface compat only.
      */
     virtual void Reset();
     
     /**
      * True in fragment mode and during synchronous document.write
      */
     virtual bool CanInterrupt();
 
@@ -248,35 +248,16 @@ class nsHtml5Parser : public nsIParser,
 
     /**
      * True if this is a script-created HTML5 parser.
      */
     virtual bool IsScriptCreated();
 
     /* End nsIParser  */
 
-    /**
-     * Invoke the fragment parsing algorithm (innerHTML).
-     *
-     * @param aSourceBuffer the string being set as innerHTML
-     * @param aTargetNode the target container
-     * @param aContextLocalName local name of context node
-     * @param aContextNamespace namespace of context node
-     * @param aQuirks true to make <table> not close <p>
-     * @param aPreventScriptExecution true to prevent scripts from executing;
-     * don't set to false when parsing into a target node that has been bound
-     * to tree.
-     */
-    nsresult ParseHtml5Fragment(const nsAString& aSourceBuffer,
-                                nsIContent* aTargetNode,
-                                nsIAtom* aContextLocalName,
-                                PRInt32 aContextNamespace,
-                                bool aQuirks,
-                                bool aPreventScriptExecution);
-
     // Not from an external interface
     // Non-inherited methods
 
   public:
 
     /**
      * Initializes the parser to load from a channel.
      */
new file mode 100644
--- /dev/null
+++ b/parser/html/nsHtml5StringParser.cpp
@@ -0,0 +1,137 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Pierre Phaneuf <pp@ludusdesign.com>
+ *   Henri Sivonen <hsivonen@iki.fi>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsHtml5StringParser.h"
+#include "nsHtml5TreeOpExecutor.h"
+#include "nsHtml5TreeBuilder.h"
+#include "nsHtml5Tokenizer.h"
+#include "nsIContent.h"
+#include "nsIDocument.h"
+#include "nsIDOMDocumentFragment.h"
+#include "nsHtml5DependentUTF16Buffer.h"
+
+NS_IMPL_ISUPPORTS0(nsHtml5StringParser)
+
+nsHtml5StringParser::nsHtml5StringParser()
+  : mExecutor(new nsHtml5TreeOpExecutor())
+  , mTreeBuilder(new nsHtml5TreeBuilder(mExecutor, nsnull))
+  , mTokenizer(new nsHtml5Tokenizer(mTreeBuilder, false))
+{
+  MOZ_COUNT_CTOR(nsHtml5StringParser);
+  mAtomTable.Init(); // we aren't checking for OOM anyway...
+  mTokenizer->setInterner(&mAtomTable);
+}
+
+nsHtml5StringParser::~nsHtml5StringParser()
+{
+  MOZ_COUNT_DTOR(nsHtml5StringParser);
+}
+
+nsresult
+nsHtml5StringParser::ParseHtml5Fragment(const nsAString& aSourceBuffer,
+                                        nsIContent* aTargetNode,
+                                        nsIAtom* aContextLocalName,
+                                        PRInt32 aContextNamespace,
+                                        bool aQuirks,
+                                        bool aPreventScriptExecution)
+{
+  NS_ENSURE_TRUE(aSourceBuffer.Length() <= PR_INT32_MAX,
+      NS_ERROR_OUT_OF_MEMORY);
+  nsIDocument* doc = aTargetNode->OwnerDoc();
+
+  nsIURI* uri = doc->GetDocumentURI();
+  NS_ENSURE_TRUE(uri, NS_ERROR_NOT_AVAILABLE);
+
+  mExecutor->EnableFragmentMode(aPreventScriptExecution);
+
+  mExecutor->Init(doc, uri, nsnull, nsnull);
+
+  mExecutor->SetParser(this);
+  mExecutor->SetNodeInfoManager(doc->NodeInfoManager());
+
+  nsIContent* target = aTargetNode;
+  mTreeBuilder->setFragmentContext(aContextLocalName,
+                                   aContextNamespace,
+                                   &target,
+                                   aQuirks);
+
+#ifdef DEBUG
+  if (!aPreventScriptExecution) {
+    NS_ASSERTION(!aTargetNode->IsInDoc(),
+        "If script execution isn't prevented, "
+        "the target node must not be in doc.");
+    nsCOMPtr<nsIDOMDocumentFragment> domFrag = do_QueryInterface(aTargetNode);
+    NS_ASSERTION(domFrag,
+        "If script execution isn't prevented, must parse to DOM fragment.");
+  }
+#endif
+
+  NS_PRECONDITION(!mExecutor->HasStarted(),
+                  "Tried to start parse without initializing the parser.");
+  mTreeBuilder->setScriptingEnabled(mExecutor->IsScriptEnabled());
+  mTokenizer->start();
+  mExecutor->Start(); // Don't call WillBuildModel in fragment case
+  if (!aSourceBuffer.IsEmpty()) {
+    bool lastWasCR = false;
+    nsHtml5DependentUTF16Buffer buffer(aSourceBuffer);
+    while (buffer.hasMore()) {
+      buffer.adjust(lastWasCR);
+      lastWasCR = false;
+      if (buffer.hasMore()) {
+        lastWasCR = mTokenizer->tokenizeBuffer(&buffer);
+        if (mTreeBuilder->HasScript()) {
+          // Flush on each script, because the execution prevention code
+          // can handle at most one script per flush.
+          mTreeBuilder->Flush(); // Move ops to the executor
+          mExecutor->FlushDocumentWrite(); // run the ops
+        }
+      }
+    }
+  }
+  mTokenizer->eof();
+  mTreeBuilder->StreamEnded();
+  mTreeBuilder->Flush();
+  mExecutor->FlushDocumentWrite();
+  mTokenizer->end();
+  mExecutor->DropParserAndPerfHint();
+  mExecutor->DropHeldElements();
+  mTreeBuilder->DropHandles();
+  mAtomTable.Clear();
+  mExecutor->Reset();
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/parser/html/nsHtml5StringParser.h
@@ -0,0 +1,101 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Henri Sivonen <hsivonen@iki.fi>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nsHtml5StringParser_h_
+#define nsHtml5StringParser_h_
+
+#include "nsHtml5AtomTable.h"
+#include "nsParserBase.h"
+
+class nsHtml5TreeOpExecutor;
+class nsHtml5TreeBuilder;
+class nsHtml5Tokenizer;
+class nsIContent;
+
+class nsHtml5StringParser : public nsParserBase
+{
+  public:
+
+    NS_DECL_ISUPPORTS
+
+    nsHtml5StringParser();
+    virtual ~nsHtml5StringParser();
+
+    /**
+     * Invoke the fragment parsing algorithm (innerHTML).
+     *
+     * @param aSourceBuffer the string being set as innerHTML
+     * @param aTargetNode the target container
+     * @param aContextLocalName local name of context node
+     * @param aContextNamespace namespace of context node
+     * @param aQuirks true to make <table> not close <p>
+     * @param aPreventScriptExecution true to prevent scripts from executing;
+     * don't set to false when parsing into a target node that has been bound
+     * to tree.
+     */
+    nsresult ParseHtml5Fragment(const nsAString& aSourceBuffer,
+                                nsIContent* aTargetNode,
+                                nsIAtom* aContextLocalName,
+                                PRInt32 aContextNamespace,
+                                bool aQuirks,
+                                bool aPreventScriptExecution);
+
+  private:
+
+    /**
+     * The tree operation executor
+     */
+    nsRefPtr<nsHtml5TreeOpExecutor>     mExecutor;
+
+    /**
+     * The HTML5 tree builder
+     */
+    const nsAutoPtr<nsHtml5TreeBuilder> mTreeBuilder;
+
+    /**
+     * The HTML5 tokenizer
+     */
+    const nsAutoPtr<nsHtml5Tokenizer>   mTokenizer;
+
+    /**
+     * The scoped atom table
+     */
+    nsHtml5AtomTable                    mAtomTable;
+
+};
+
+#endif // nsHtml5StringParser_h_
--- a/parser/html/nsHtml5TreeOpExecutor.cpp
+++ b/parser/html/nsHtml5TreeOpExecutor.cpp
@@ -191,17 +191,17 @@ nsHtml5TreeOpExecutor::WillInterrupt()
 NS_IMETHODIMP
 nsHtml5TreeOpExecutor::WillResume()
 {
   NS_NOTREACHED("Don't call. For interface compat only.");
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
-nsHtml5TreeOpExecutor::SetParser(nsIParser* aParser)
+nsHtml5TreeOpExecutor::SetParser(nsParserBase* aParser)
 {
   mParser = aParser;
   return NS_OK;
 }
 
 void
 nsHtml5TreeOpExecutor::FlushPendingNotifications(mozFlushType aType)
 {
@@ -421,17 +421,17 @@ nsHtml5TreeOpExecutor::RunFlushLoop()
   SAMPLE_LABEL("html5", "RunFlushLoop");
   if (mRunFlushLoopOnStack) {
     // There's already a RunFlushLoop() on the call stack.
     return;
   }
   
   nsHtml5FlushLoopGuard guard(this); // this is also the self-kungfu!
   
-  nsCOMPtr<nsIParser> parserKungFuDeathGrip(mParser);
+  nsCOMPtr<nsISupports> parserKungFuDeathGrip(mParser);
 
   // Remember the entry time
   (void) nsContentSink::WillParseImpl();
 
   for (;;) {
     if (!mParser) {
       // Parse has terminated.
       mOpQueue.Clear(); // clear in order to be able to assert in destructor
@@ -588,17 +588,17 @@ nsHtml5TreeOpExecutor::FlushDocumentWrit
     // XXX Can this happen? In case it can, let's avoid crashing.
     return;
   }
 
   mFlushState = eInFlush;
 
   // avoid crashing near EOF
   nsRefPtr<nsHtml5TreeOpExecutor> kungFuDeathGrip(this);
-  nsCOMPtr<nsIParser> parserKungFuDeathGrip(mParser);
+  nsRefPtr<nsParserBase> parserKungFuDeathGrip(mParser);
 
   NS_ASSERTION(!mReadingFromStage,
     "Got doc write flush when reading from stage");
 
 #ifdef DEBUG
   mStage.AssertEmpty();
 #endif
   
@@ -741,28 +741,28 @@ nsHtml5TreeOpExecutor::RunScript(nsICont
     NS_ASSERTION(!block, "Defer or async script tried to block.");
     return;
   }
   
   NS_ASSERTION(mFlushState == eNotFlushing, "Tried to run script when flushing.");
 
   mReadingFromStage = false;
   
-  sele->SetCreatorParser(mParser);
+  sele->SetCreatorParser(GetParser());
 
   // Copied from nsXMLContentSink
   // Now tell the script that it's ready to go. This may execute the script
   // or return true, or neither if the script doesn't need executing.
   bool block = sele->AttemptToExecute();
 
   // If the act of insertion evaluated the script, we're fine.
   // Else, block the parser till the script has loaded.
   if (block) {
     if (mParser) {
-      mParser->BlockParser();
+      GetParser()->BlockParser();
     }
   } else {
     // mParser may have been nulled out by now, but the flusher deals
 
     // If this event isn't needed, it doesn't do anything. It is sometimes
     // necessary for the parse to continue after complex situations.
     nsHtml5TreeOpExecutor::ContinueInterruptedParsingAsync();
   }
@@ -828,22 +828,22 @@ nsHtml5TreeOpExecutor::GetTokenizer()
 {
   return GetParser()->GetTokenizer();
 }
 
 void
 nsHtml5TreeOpExecutor::Reset()
 {
   DropHeldElements();
-  mReadingFromStage = false;
   mOpQueue.Clear();
   mStarted = false;
   mFlushState = eNotFlushing;
   mRunFlushLoopOnStack = false;
-  NS_ASSERTION(!mBroken, "Fragment parser got broken.");
+  NS_ASSERTION(!mReadingFromStage, "String parser reading from stage?");
+  NS_ASSERTION(!mBroken, "String parser got broken.");
 }
 
 void
 nsHtml5TreeOpExecutor::DropHeldElements()
 {
   mScriptLoader = nsnull;
   mDocument = nsnull;
   mNodeInfoManager = nsnull;
--- a/parser/html/nsHtml5TreeOpExecutor.h
+++ b/parser/html/nsHtml5TreeOpExecutor.h
@@ -174,17 +174,17 @@ class nsHtml5TreeOpExecutor : public nsC
     /**
      * Unimplemented. For interface compat only.
      */
     NS_IMETHOD WillResume();
 
     /**
      * Sets the parser.
      */
-    NS_IMETHOD SetParser(nsIParser* aParser);
+    NS_IMETHOD SetParser(nsParserBase* aParser);
 
     /**
      * No-op for backwards compat.
      */
     virtual void FlushPendingNotifications(mozFlushType aType);
 
     /**
      * Don't call. For interface compat only.
--- a/parser/htmlparser/public/Makefile.in
+++ b/parser/htmlparser/public/Makefile.in
@@ -62,16 +62,17 @@ EXPORTS = \
 		nsIParserService.h          \
 		nsHTMLTagList.h             \
 		nsHTMLTags.h                \
 		nsHTMLTokens.h              \
 		nsScannerString.h           \
 		nsParserCIID.h              \
 		nsToken.h                   \
 		nsParserConstants.h         \
+		nsParserBase.h             \
 		$(NULL)
 
 ifdef MOZ_DEBUG
 EXPORTS += \
 		nsILoggingSink.h \
 		$(NULL)
 endif
 
--- a/parser/htmlparser/public/nsIContentSink.h
+++ b/parser/htmlparser/public/nsIContentSink.h
@@ -49,17 +49,17 @@
  * content-sink model building process. There is another one that you may care 
  * about more, which is the IHTMLContentSink interface. (See that file for details).
  */
 #include "nsISupports.h"
 #include "nsStringGlue.h"
 #include "mozFlushType.h"
 #include "nsIDTD.h"
 
-class nsIParser;
+class nsParserBase;
 
 #define NS_ICONTENT_SINK_IID \
 { 0xcf9a7cbb, 0xfcbc, 0x4e13, \
   { 0x8e, 0xf5, 0x18, 0xef, 0x2d, 0x3d, 0x58, 0x29 } }
 
 class nsIContentSink : public nsISupports {
 public:
 
@@ -117,17 +117,17 @@ public:
   NS_IMETHOD WillResume(void)=0;
 
   /**
    * This method gets called by the parser so that the content
    * sink can retain a reference to the parser. The expectation
    * is that the content sink will drop the reference when it
    * gets the DidBuildModel notification i.e. when parsing is done.
    */
-  NS_IMETHOD SetParser(nsIParser* aParser)=0;
+  NS_IMETHOD SetParser(nsParserBase* aParser)=0;
 
   /**
    * Flush content so that the content model is in sync with the state
    * of the sink.
    *
    * @param aType the type of flush to perform
    */
   virtual void FlushPendingNotifications(mozFlushType aType)=0;
--- a/parser/htmlparser/public/nsIDTD.h
+++ b/parser/htmlparser/public/nsIDTD.h
@@ -54,19 +54,18 @@
  * */
 
 #include "nsISupports.h"
 #include "nsStringGlue.h"
 #include "prtypes.h"
 #include "nsITokenizer.h"
 
 #define NS_IDTD_IID \
-{ 0xcc374204, 0xcea2, 0x41a2, \
-  { 0xb2, 0x7f, 0x83, 0x75, 0xe2, 0xcf, 0x97, 0xcf } }
-
+{ 0x3de05873, 0xefa7, 0x410d, \
+  { 0xa4, 0x61, 0x80, 0x33, 0xaf, 0xd9, 0xe3, 0x26 } }
 
 enum eAutoDetectResult {
     eUnknownDetect,
     eValidDetect,
     ePrimaryDetect,
     eInvalidDetect
 };
 
@@ -104,26 +103,23 @@ public:
      */
     NS_IMETHOD DidBuildModel(nsresult anErrorCode) = 0;
 
     /**
      * Called (possibly repeatedly) by the parser to parse tokens and construct
      * the document model via the sink provided to WillBuildModel.
      *
      * @param   aTokenizer - tokenizer providing the token stream to be parsed
-     * @param   aCanInterrupt - informs the DTD whether the parser can handle
-     *                          interruptions of the model building process
      * @param   aCountLines - informs the DTD whether to count newlines
      *                        (not wanted, e.g., when handling document.write)
      * @param   aCharsetPtr - address of an nsCString containing the charset
      *                        that the DTD should use (pointer in case the DTD
      *                        opts to ignore this parameter)
      */
     NS_IMETHOD BuildModel(nsITokenizer* aTokenizer,
-                          bool aCanInterrupt,
                           bool aCountLines,
                           const nsCString* aCharsetPtr) = 0;
 
     /**
      * This method is called to determine whether or not a tag of one
      * type can contain a tag of another type.
      *
      * @update  gess 3/25/98
@@ -164,15 +160,15 @@ public:
     NS_IMETHOD_(nsDTDMode) GetMode() const = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIDTD, NS_IDTD_IID)
 
 #define NS_DECL_NSIDTD \
     NS_IMETHOD WillBuildModel(  const CParserContext& aParserContext, nsITokenizer* aTokenizer, nsIContentSink* aSink);\
     NS_IMETHOD DidBuildModel(nsresult anErrorCode);\
-    NS_IMETHOD BuildModel(nsITokenizer* aTokenizer, bool aCanInterrupt, bool aCountLines, const nsCString* aCharsetPtr);\
+    NS_IMETHOD BuildModel(nsITokenizer* aTokenizer, bool aCountLines, const nsCString* aCharsetPtr);\
     NS_IMETHOD_(bool) CanContain(PRInt32 aParent,PRInt32 aChild) const;\
     NS_IMETHOD_(bool) IsContainer(PRInt32 aTag) const;\
     NS_IMETHOD_(void)  Terminate();\
     NS_IMETHOD_(PRInt32) GetType();\
     NS_IMETHOD_(nsDTDMode) GetMode() const;
 #endif /* nsIDTD_h___ */
--- a/parser/htmlparser/public/nsIParser.h
+++ b/parser/htmlparser/public/nsIParser.h
@@ -48,20 +48,21 @@
  **/
 
 #include "nsISupports.h"
 #include "nsIStreamListener.h"
 #include "nsIDTD.h"
 #include "nsStringGlue.h"
 #include "nsTArray.h"
 #include "nsIAtom.h"
+#include "nsParserBase.h"
 
 #define NS_IPARSER_IID \
-{ 0x11a4f41f, 0x7044, 0x4c57, \
-  { 0xb3, 0xa4, 0xed, 0x79, 0xc7, 0xc4, 0x61, 0x99 } }
+{ 0xd064f0d6, 0x44e3, 0x4366, \
+  { 0xa7, 0x05, 0xcf, 0x7a, 0x91, 0x26, 0x14, 0xb6 } }
 
 // {41421C60-310A-11d4-816F-000064657374}
 #define NS_IDEBUG_DUMP_CONTENT_IID \
 { 0x41421c60, 0x310a, 0x11d4, \
 { 0x81, 0x6f, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } }
 
 class nsIContentSink;
 class nsIRequestObserver;
@@ -124,17 +125,17 @@ public:
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIDebugDumpContent, NS_IDEBUG_DUMP_CONTENT_IID)
 
 /**
  *  This class defines the iparser interface. This XPCOM
  *  inteface is all that parser clients ever need to see.
  */
-class nsIParser : public nsISupports {
+class nsIParser : public nsParserBase {
   public:
 
     NS_DECLARE_STATIC_IID_ACCESSOR(NS_IPARSER_IID)
 
     /**
      * Select given content sink into parser for parser output
      * @update	gess5/11/98
      * @param   aSink is the new sink to be used by parser
@@ -269,22 +270,16 @@ class nsIParser : public nsISupports {
      *  @return  NS_OK if succeeded else ERROR.
      */
 
     NS_IMETHOD CancelParsingEvents() = 0;
 
     virtual void Reset() = 0;
 
     /**
-     * True if the parser can currently be interrupted. Returns false when
-     * parsing for example document.write or innerHTML.
-     */
-    virtual bool CanInterrupt() = 0;
-
-    /**
      * True if the insertion point (per HTML5) is defined.
      */
     virtual bool IsInsertionPointDefined() = 0;
 
     /**
      * Call immediately before starting to evaluate a parser-inserted script.
      */
     virtual void BeginEvaluatingParserInsertedScript() = 0;
new file mode 100644
--- /dev/null
+++ b/parser/htmlparser/public/nsParserBase.h
@@ -0,0 +1,53 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is parser base code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Henri Sivonen <hsivonen@iki.fi>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nsParserBase_h_
+#define nsParserBase_h_
+
+#include "nsIChannel.h"
+
+class nsParserBase : public nsISupports
+{
+  public:
+    virtual bool IsParserEnabled() { return true; }
+    NS_IMETHOD GetChannel(nsIChannel** aChannel) {
+      *aChannel = nsnull;
+      return NS_OK;
+    };
+};
+
+#endif // nsParserBase_h_
--- a/parser/htmlparser/src/CNavDTD.cpp
+++ b/parser/htmlparser/src/CNavDTD.cpp
@@ -220,17 +220,16 @@ CNavDTD::WillBuildModel(const CParserCon
 
   }
 
   return result;
 }
 
 NS_IMETHODIMP
 CNavDTD::BuildModel(nsITokenizer* aTokenizer,
-                    bool aCanInterrupt,
                     bool aCountLines,
                     const nsCString*)
 {
   NS_PRECONDITION(mBodyContext != nsnull,
                   "Create a context before calling build model");
 
   nsresult result = NS_OK;
 
@@ -305,21 +304,19 @@ CNavDTD::BuildModel(nsITokenizer* aToken
       result = HandleToken(theToken);
     } else {
       result = NS_ERROR_HTMLPARSER_STOPPARSING;
       break;
     }
 
     if (NS_ERROR_HTMLPARSER_INTERRUPTED == mSink->DidProcessAToken()) {
       // The content sink has requested that DTD interrupt processing tokens
-      // So we need to make sure the parser is in a state where it can be
-      // interrupted (e.g., not in a document.write).
-      // We also need to make sure that an interruption does not override
+      // We need to make sure that an interruption does not override
       // a request to block the parser.
-      if (aCanInterrupt && NS_SUCCEEDED(result)) {
+      if (NS_SUCCEEDED(result)) {
         result = NS_ERROR_HTMLPARSER_INTERRUPTED;
         break;
       }
     }
   }
 
   mTokenizer = oldTokenizer;
   return result;
@@ -333,22 +330,20 @@ CNavDTD::BuildNeglectedTarget(eHTMLTags 
   NS_ASSERTION(mTokenAllocator, "unable to create tokens without an allocator.");
   if (!mTokenizer || !mTokenAllocator) {
     return NS_OK;
   }
 
   CToken* target = mTokenAllocator->CreateTokenOfType(aType, aTarget);
   NS_ENSURE_TRUE(target, NS_ERROR_OUT_OF_MEMORY);
   mTokenizer->PushTokenFront(target);
-  // Always safe to disallow interruptions, so it doesn't matter that we've
-  // forgotten the aCanInterrupt parameter to BuildModel.  Also, BuildModel
+  // Also, BuildModel
   // doesn't seem to care about the charset, and at this point we have no idea
-  // what the charset was, so 0 can and must suffice.  If either of these
-  // values mattered, we'd want to store them as data members in BuildModel.
-  return BuildModel(mTokenizer, false, mCountLines, 0);
+  // what the charset was, so 0 can and must suffice.
+  return BuildModel(mTokenizer, mCountLines, 0);
 }
 
 NS_IMETHODIMP
 CNavDTD::DidBuildModel(nsresult anErrorCode)
 {
   nsresult result = NS_OK;
 
   if (mSink) {
--- a/parser/htmlparser/src/nsExpatDriver.cpp
+++ b/parser/htmlparser/src/nsExpatDriver.cpp
@@ -1297,17 +1297,16 @@ nsExpatDriver::WillBuildModel(const CPar
   // XML must detect invalid character convertion
   aParserContext.mScanner->OverrideReplacementCharacter(0xffff);
 
   return mInternalState;
 }
 
 NS_IMETHODIMP
 nsExpatDriver::BuildModel(nsITokenizer* aTokenizer,
-                          bool,// aCanInterrupt,
                           bool,// aCountLines,
                           const nsCString*)// aCharsetPtr)
 {
   return mInternalState;
 }
 
 NS_IMETHODIMP
 nsExpatDriver::DidBuildModel(nsresult anErrorCode)
--- a/parser/htmlparser/src/nsLoggingSink.cpp
+++ b/parser/htmlparser/src/nsLoggingSink.cpp
@@ -61,17 +61,16 @@ NS_NewHTMLLoggingSink(nsIContentSink** a
   }
   return it->QueryInterface(kIContentSinkIID, (void**) aInstancePtrResult);
 }
 
 nsLoggingSink::nsLoggingSink() {
   mOutput = 0;
   mLevel=-1;
   mSink=0;
-  mParser=0;
 }
 
 nsLoggingSink::~nsLoggingSink() { 
   mSink=0;
   if(mOutput && mAutoDeleteOutput) {
     delete mOutput;
   }
   mOutput=0;
@@ -147,30 +146,24 @@ nsLoggingSink::WillResume() {
   if(mSink) {
     theResult=mSink->WillResume();
   }
   
   return theResult;
 }
 
 NS_IMETHODIMP
-nsLoggingSink::SetParser(nsIParser* aParser)  {
+nsLoggingSink::SetParser(nsParserBase* aParser)  {
   nsresult theResult=NS_OK;
 
   //proxy the call to the real sink if you have one.
   if(mSink) {
     theResult=mSink->SetParser(aParser);
   }
   
-  NS_IF_RELEASE(mParser);
-  
-  mParser = aParser;
-  
-  NS_IF_ADDREF(mParser);
-
   return theResult;
 }
 
 NS_IMETHODIMP
 nsLoggingSink::OpenContainer(const nsIParserNode& aNode) {
 
   OpenNode("container", aNode); //do the real logging work...
 
--- a/parser/htmlparser/src/nsLoggingSink.h
+++ b/parser/htmlparser/src/nsLoggingSink.h
@@ -60,17 +60,17 @@ public:
   NS_DECL_ISUPPORTS
 
   // nsIContentSink
   NS_IMETHOD WillParse();
   NS_IMETHOD WillBuildModel(nsDTDMode aDTDMode);
   NS_IMETHOD DidBuildModel(bool aTerminated);
   NS_IMETHOD WillInterrupt();
   NS_IMETHOD WillResume();
-  NS_IMETHOD SetParser(nsIParser* aParser);
+  NS_IMETHOD SetParser(nsParserBase* aParser);
   NS_IMETHOD OpenContainer(const nsIParserNode& aNode);
   NS_IMETHOD CloseContainer(const nsHTMLTag aTag);
   NS_IMETHOD AddLeaf(const nsIParserNode& aNode);
   NS_IMETHOD AddComment(const nsIParserNode& aNode);
   NS_IMETHOD AddProcessingInstruction(const nsIParserNode& aNode);
   NS_IMETHOD AddDocTypeDecl(const nsIParserNode& aNode);
   virtual void FlushPendingNotifications(mozFlushType aType) { }
   NS_IMETHOD SetDocumentCharset(nsACString& aCharset) { return NS_OK; }
@@ -101,13 +101,12 @@ public:
   nsresult GetNewCString(const nsAString& aValue, char** aResult);
   bool WillWriteAttributes(const nsIParserNode& aNode);
 
 protected:
   PRFileDesc          *mOutput;
   int                  mLevel;
   nsIHTMLContentSink  *mSink;
   bool                 mAutoDeleteOutput;
-  nsIParser*           mParser;
 };
 
 #endif
 
--- a/parser/htmlparser/src/nsParser.cpp
+++ b/parser/htmlparser/src/nsParser.cpp
@@ -75,17 +75,16 @@
 #include "mozilla/Mutex.h"
 #include "nsParserConstants.h"
 
 using namespace mozilla;
 
 #define NS_PARSER_FLAG_PARSER_ENABLED         0x00000002
 #define NS_PARSER_FLAG_OBSERVERS_ENABLED      0x00000004
 #define NS_PARSER_FLAG_PENDING_CONTINUE_EVENT 0x00000008
-#define NS_PARSER_FLAG_CAN_INTERRUPT          0x00000010
 #define NS_PARSER_FLAG_FLUSH_TOKENS           0x00000020
 #define NS_PARSER_FLAG_CAN_TOKENIZE           0x00000040
 
 static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
 static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
 static NS_DEFINE_IID(kIParserIID, NS_IPARSER_IID);
 
 //-------------- Begin ParseContinue Event Definition ------------------------
@@ -1227,22 +1226,16 @@ void nsParser::HandleParserContinueEvent
   mContinueEvent = nsnull;
 
   NS_ASSERTION(IsOkToProcessNetworkData(),
                "Interrupted in the middle of a script?");
   ContinueInterruptedParsing();
 }
 
 bool
-nsParser::CanInterrupt()
-{
-  return (mFlags & NS_PARSER_FLAG_CAN_INTERRUPT) != 0;
-}
-
-bool
 nsParser::IsInsertionPointDefined()
 {
   return true;
 }
 
 void
 nsParser::BeginEvaluatingParserInsertedScript()
 {
@@ -1259,26 +1252,16 @@ nsParser::MarkAsNotScriptCreated(const c
 }
 
 bool
 nsParser::IsScriptCreated()
 {
   return false;
 }
 
-void
-nsParser::SetCanInterrupt(bool aCanInterrupt)
-{
-  if (aCanInterrupt) {
-    mFlags |= NS_PARSER_FLAG_CAN_INTERRUPT;
-  } else {
-    mFlags &= ~NS_PARSER_FLAG_CAN_INTERRUPT;
-  }
-}
-
 /**
  *  This is the main controlling routine in the parsing process.
  *  Note that it may get called multiple times for the same scanner,
  *  since this is a pushed based system, and all the tokens may
  *  not have been consumed by the scanner during a given invocation
  *  of this method.
  */
 NS_IMETHODIMP
@@ -1596,26 +1579,24 @@ nsParser::ResumeParse(bool allowIteratio
           // as if it was read from the input stream.
           // Adding UngetReadable() per vidur!!
           mParserContext->mScanner->UngetReadable(mUnusedInput);
           mUnusedInput.Truncate(0);
         }
 
         // Only allow parsing to be interrupted in the subsequent call to
         // build model.
-        SetCanInterrupt(aCanInterrupt);
         nsresult theTokenizerResult = (mFlags & NS_PARSER_FLAG_CAN_TOKENIZE)
                                       ? Tokenize(aIsFinalChunk)
                                       : NS_OK;
         result = BuildModel();
 
         if (result == NS_ERROR_HTMLPARSER_INTERRUPTED && aIsFinalChunk) {
           PostContinueEvent();
         }
-        SetCanInterrupt(false);
 
         theIterationIsOk = theTokenizerResult != kEOF &&
                            result != NS_ERROR_HTMLPARSER_INTERRUPTED;
 
         // 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.
@@ -1695,21 +1676,19 @@ nsParser::BuildModel()
 
   nsresult result = NS_OK;
   if (mParserContext) {
     result = mParserContext->GetTokenizer(mDTD, mSink, theTokenizer);
   }
 
   if (NS_SUCCEEDED(result)) {
     if (mDTD) {
-      // XXXbenjamn CanInterrupt() and !inDocWrite appear to be covariant.
       bool inDocWrite = !!mParserContext->mPrevContext;
       result = mDTD->BuildModel(theTokenizer,
                                 // ignore interruptions in document.write
-                                CanInterrupt() && !inDocWrite,
                                 !inDocWrite, // don't count lines in document.write
                                 &mCharset);
     }
   } else {
     mInternalState = result = NS_ERROR_HTMLPARSER_BADTOKENIZER;
   }
   return result;
 }
--- a/parser/htmlparser/src/nsParser.h
+++ b/parser/htmlparser/src/nsParser.h
@@ -304,24 +304,16 @@ class nsParser : public nsIParser,
 
     /**
      *  Removes continue parsing events
      *  @update  kmcclusk 5/18/98
      */
 
     NS_IMETHODIMP CancelParsingEvents();
 
-    /**  
-     *  Indicates whether the parser is in a state where it
-     *  can be interrupted.
-     *  @return true if parser can be interrupted, false if it can not be interrupted.
-     *  @update  kmcclusk 5/18/98
-     */
-    virtual bool CanInterrupt();
-
     /**
      * Return true.
      */
     virtual bool IsInsertionPointDefined();
 
     /**
      * No-op.
      */
--- a/parser/xml/src/nsSAXXMLReader.cpp
+++ b/parser/xml/src/nsSAXXMLReader.cpp
@@ -102,17 +102,17 @@ nsSAXXMLReader::DidBuildModel(bool aTerm
 {
   if (mContentHandler)
     return mContentHandler->EndDocument();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsSAXXMLReader::SetParser(nsIParser *aParser)
+nsSAXXMLReader::SetParser(nsParserBase *aParser)
 {
   return NS_OK;
 }
 
 // nsIExtendedExpatSink
 NS_IMETHODIMP
 nsSAXXMLReader::HandleStartElement(const PRUnichar *aName,
                                    const PRUnichar **aAtts,
--- a/parser/xml/src/nsSAXXMLReader.h
+++ b/parser/xml/src/nsSAXXMLReader.h
@@ -74,17 +74,17 @@ public:
   //nsIContentSink
   NS_IMETHOD WillParse()
   {
     return NS_OK;
   }
 
   NS_IMETHOD WillBuildModel(nsDTDMode aDTDMode);
   NS_IMETHOD DidBuildModel(bool aTerminated);
-  NS_IMETHOD SetParser(nsIParser* aParser);
+  NS_IMETHOD SetParser(nsParserBase* aParser);
   
   NS_IMETHOD WillInterrupt()
   {
     return NS_OK;
   }
 
   NS_IMETHOD WillResume()
   {
--- a/rdf/base/src/nsRDFContentSink.cpp
+++ b/rdf/base/src/nsRDFContentSink.cpp
@@ -164,17 +164,17 @@ public:
     NS_DECL_NSIEXPATSINK
 
     // nsIContentSink
     NS_IMETHOD WillParse(void);
     NS_IMETHOD WillBuildModel(nsDTDMode aDTDMode);
     NS_IMETHOD DidBuildModel(bool aTerminated);
     NS_IMETHOD WillInterrupt(void);
     NS_IMETHOD WillResume(void);
-    NS_IMETHOD SetParser(nsIParser* aParser);  
+    NS_IMETHOD SetParser(nsParserBase* aParser);
     virtual void FlushPendingNotifications(mozFlushType aType) { }
     NS_IMETHOD SetDocumentCharset(nsACString& aCharset) { return NS_OK; }
     virtual nsISupports *GetTarget() { return nsnull; }
 
     // nsIRDFContentSink
     NS_IMETHOD Init(nsIURI* aURL);
     NS_IMETHOD SetDataSource(nsIRDFDataSource* aDataSource);
     NS_IMETHOD GetDataSource(nsIRDFDataSource*& aDataSource);
@@ -638,17 +638,17 @@ RDFContentSinkImpl::WillResume(void)
         nsCOMPtr<nsIRDFXMLSink> sink = do_QueryInterface(mDataSource);
         if (sink)
             return sink->Resume();
     }
     return NS_OK;
 }
 
 NS_IMETHODIMP 
-RDFContentSinkImpl::SetParser(nsIParser* aParser)
+RDFContentSinkImpl::SetParser(nsParserBase* aParser)
 {
     return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////
 // nsIRDFContentSink interface
 
 NS_IMETHODIMP
--- a/toolkit/components/places/nsPlacesImportExportService.cpp
+++ b/toolkit/components/places/nsPlacesImportExportService.cpp
@@ -350,17 +350,17 @@ public:
                 bool aIsImportDefaults);
 
   NS_DECL_ISUPPORTS
 
   // nsIContentSink (superclass of nsIHTMLContentSink)
   NS_IMETHOD WillParse() { return NS_OK; }
   NS_IMETHOD WillInterrupt() { return NS_OK; }
   NS_IMETHOD WillResume() { return NS_OK; }
-  NS_IMETHOD SetParser(nsIParser* aParser) { return NS_OK; }
+  NS_IMETHOD SetParser(nsParserBase* aParser) { return NS_OK; }
   virtual void FlushPendingNotifications(mozFlushType aType) { }
   NS_IMETHOD SetDocumentCharset(nsACString& aCharset) { return NS_OK; }
   virtual nsISupports *GetTarget() { return nsnull; }
 
   // nsIHTMLContentSink
   NS_IMETHOD OpenHead() { return NS_OK; }
   NS_IMETHOD BeginContext(PRInt32 aPosition) { return NS_OK; }
   NS_IMETHOD EndContext(PRInt32 aPosition) { return NS_OK; }