Bug 386769 - "Make setting innerHTML faster". r=jst, sr=peterv, a=blocking1.9.
authorbent.mozilla@gmail.com
Fri, 08 Feb 2008 14:07:51 -0800
changeset 11423 1492999229c56221030dce7b155a9146b3ab81b9
parent 11422 a91e7ccb66e2f43521fdcba9fbab2d5cb8b8bc7d
child 11424 b3a57cbf482ab56ed606e0d083ce3a871705b7e0
push idunknown
push userunknown
push dateunknown
reviewersjst, peterv, blocking1
bugs386769
milestone1.9b4pre
Bug 386769 - "Make setting innerHTML faster". r=jst, sr=peterv, a=blocking1.9.
content/base/public/nsIDocument.h
content/base/src/nsContentSink.cpp
content/base/src/nsContentSink.h
content/base/src/nsContentUtils.cpp
content/html/document/src/nsHTMLDocument.cpp
content/html/document/src/nsHTMLDocument.h
content/html/document/src/nsHTMLFragmentContentSink.cpp
content/xml/document/src/nsXMLContentSink.cpp
content/xml/document/src/nsXMLContentSink.h
content/xml/document/src/nsXMLFragmentContentSink.cpp
parser/htmlparser/public/nsIParser.h
parser/htmlparser/src/CNavDTD.cpp
parser/htmlparser/src/CNavDTD.h
parser/htmlparser/src/nsExpatDriver.cpp
parser/htmlparser/src/nsExpatDriver.h
parser/htmlparser/src/nsParser.cpp
parser/htmlparser/src/nsParser.h
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -936,16 +936,26 @@ public:
     return mJSObject;
   }
 
   void SetJSObject(JSObject *aJSObject)
   {
     mJSObject = aJSObject;
   }
 
+  // This method should return an addrefed nsIParser* or nsnull. Implementations
+  // should transfer ownership of the parser to the caller.
+  virtual already_AddRefed<nsIParser> GetFragmentParser() {
+    return nsnull;
+  }
+
+  virtual void SetFragmentParser(nsIParser* aParser) {
+    // Do nothing.
+  }
+
 protected:
   ~nsIDocument()
   {
     // XXX The cleanup of mNodeInfoManager (calling DropDocumentReference and
     //     releasing it) happens in the nsDocument destructor. We'd prefer to
     //     do it here but nsNodeInfoManager is a concrete class that we don't
     //     want to expose to users of the nsIDocument API outside of Gecko.
     // XXX Same thing applies to mBindingManager
--- a/content/base/src/nsContentSink.cpp
+++ b/content/base/src/nsContentSink.cpp
@@ -142,20 +142,27 @@ nsScriptLoaderObserverProxy::ScriptEvalu
   if (inner) {
     return inner->ScriptEvaluated(aResult, aElement, aIsInline);
   }
 
   return NS_OK;
 }
 
 
-NS_IMPL_ISUPPORTS3(nsContentSink,
-                   nsICSSLoaderObserver,
-                   nsISupportsWeakReference,
-                   nsIScriptLoaderObserver)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsContentSink)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(nsContentSink)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsContentSink)
+  NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver)
+  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
+  NS_INTERFACE_MAP_ENTRY(nsIScriptLoaderObserver)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIScriptLoaderObserver)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTION_2(nsContentSink, mDocument, mParser)
 
 nsContentSink::nsContentSink()
 {
   // We have a zeroing operator new
   NS_ASSERTION(mLayoutStarted == PR_FALSE, "What?");
   NS_ASSERTION(mDynamicLowerValue == PR_FALSE, "What?");
   NS_ASSERTION(mParsing == PR_FALSE, "What?");
   NS_ASSERTION(mLastSampledUserEventTime == 0, "What?");
--- a/content/base/src/nsContentSink.h
+++ b/content/base/src/nsContentSink.h
@@ -57,16 +57,17 @@
 #include "nsHashKeys.h"
 #include "nsITimer.h"
 #include "nsStubDocumentObserver.h"
 #include "nsIParserService.h"
 #include "nsIContentSink.h"
 #include "prlog.h"
 #include "nsIRequest.h"
 #include "nsTimer.h"
+#include "nsCycleCollectionParticipant.h"
 
 class nsIDocument;
 class nsIURI;
 class nsIChannel;
 class nsIDocShell;
 class nsICSSLoader;
 class nsIParser;
 class nsIAtom;
@@ -109,17 +110,19 @@ extern PRLogModuleInfo* gContentSinkLogM
 #define NS_MAX_TOKENS_DEFLECTED_IN_LOW_FREQ_MODE 200
 
 class nsContentSink : public nsICSSLoaderObserver,
                       public nsIScriptLoaderObserver,
                       public nsSupportsWeakReference,
                       public nsStubDocumentObserver,
                       public nsITimerCallback
 {
-  NS_DECL_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsContentSink,
+                                           nsIScriptLoaderObserver)
   NS_DECL_NSISCRIPTLOADEROBSERVER
 
     // nsITimerCallback
   NS_DECL_NSITIMERCALLBACK
 
   // nsICSSLoaderObserver
   NS_IMETHOD StyleSheetLoaded(nsICSSStyleSheet* aSheet, PRBool aWasAlternate,
                               nsresult aStatus);
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -73,16 +73,18 @@
 #include "nsPIDOMWindow.h"
 #include "nsIJSContextStack.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsParserCIID.h"
 #include "nsIParser.h"
 #include "nsIFragmentContentSink.h"
 #include "nsIContentSink.h"
+#include "nsIHTMLContentSink.h"
+#include "nsIXMLContentSink.h"
 #include "nsHTMLParts.h"
 #include "nsIParserService.h"
 #include "nsIServiceManager.h"
 #include "nsIAttribute.h"
 #include "nsContentList.h"
 #include "nsIHTMLDocument.h"
 #include "nsIDOMHTMLDocument.h"
 #include "nsIDOMHTMLCollection.h"
@@ -125,17 +127,16 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_
 #include "nsIURL.h"
 #include "nsXBLBinding.h"
 #include "nsXBLPrototypeBinding.h"
 #include "nsEscape.h"
 #include "nsICharsetConverterManager.h"
 #include "nsIEventListenerManager.h"
 #include "nsAttrName.h"
 #include "nsIDOMUserDataHandler.h"
-#include "nsIFragmentContentSink.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsTPtrArray.h"
 #include "nsGUIEvent.h"
 #include "nsMutationEvent.h"
 #include "nsIKBStateControl.h"
 #include "nsIMEStateManager.h"
 #include "nsContentErrors.h"
 #include "nsUnicharUtilCIID.h"
@@ -3320,21 +3321,17 @@ nsContentUtils::IsValidNodeName(nsIAtom 
 nsresult
 nsContentUtils::CreateContextualFragment(nsIDOMNode* aContextNode,
                                          const nsAString& aFragment,
                                          nsIDOMDocumentFragment** aReturn)
 {
   NS_ENSURE_ARG(aContextNode);
   *aReturn = nsnull;
 
-  // Create a new parser for this entire operation
   nsresult rv;
-  nsCOMPtr<nsIParser> parser = do_CreateInstance(kCParserCID, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-
   nsCOMPtr<nsINode> node = do_QueryInterface(aContextNode);
   NS_ENSURE_TRUE(node, NS_ERROR_NOT_AVAILABLE);
 
   // If we don't have a document here, we can't get the right security context
   // for compiling event handlers... so just bail out.
   nsCOMPtr<nsIDocument> document = node->GetOwnerDoc();
   NS_ENSURE_TRUE(document, NS_ERROR_NOT_AVAILABLE);
 
@@ -3397,27 +3394,62 @@ nsContentUtils::CreateContextualFragment
   PRBool bCaseSensitive = PR_TRUE;
   nsAutoString buf;
   document->GetContentType(buf);
   LossyCopyUTF16toASCII(buf, contentType);
   bCaseSensitive = document->IsCaseSensitive();
 
   nsCOMPtr<nsIHTMLDocument> htmlDoc(do_QueryInterface(document));
   PRBool bHTML = htmlDoc && !bCaseSensitive;
+
+  // See if the document has a cached fragment parser. nsHTMLDocument is the
+  // only one that should really have one at the moment.
+  nsCOMPtr<nsIParser> parser = document->GetFragmentParser();
+  if (parser) {
+    // Get the parser ready to use.
+    parser->Reset();
+  }
+  else {
+    // Create a new parser for this operation.
+    parser = do_CreateInstance(kCParserCID, &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  // See if the parser already has a content sink that we can reuse.
   nsCOMPtr<nsIFragmentContentSink> sink;
-  if (bHTML) {
-    rv = NS_NewHTMLFragmentContentSink(getter_AddRefs(sink));
-  } else {
-    rv = NS_NewXMLFragmentContentSink(getter_AddRefs(sink));
+  nsCOMPtr<nsIContentSink> contentsink = parser->GetContentSink();
+  if (contentsink) {
+    // Make sure it's the correct type.
+    if (bHTML) {
+      nsCOMPtr<nsIHTMLContentSink> htmlsink = do_QueryInterface(contentsink);
+      sink = do_QueryInterface(htmlsink);
+    }
+    else {
+      nsCOMPtr<nsIXMLContentSink> xmlsink = do_QueryInterface(contentsink);
+      sink = do_QueryInterface(xmlsink);
+    }
   }
-  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (!sink) {
+    // Either there was no cached content sink or it was the wrong type. Make a
+    // new one.
+    if (bHTML) {
+      rv = NS_NewHTMLFragmentContentSink(getter_AddRefs(sink));
+    } else {
+      rv = NS_NewXMLFragmentContentSink(getter_AddRefs(sink));
+    }
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    contentsink = do_QueryInterface(sink);
+    NS_ASSERTION(contentsink, "Sink doesn't QI to nsIContentSink!");
+
+    parser->SetContentSink(contentsink);
+  }
 
   sink->SetTargetDocument(document);
-  nsCOMPtr<nsIContentSink> contentsink(do_QueryInterface(sink));
-  parser->SetContentSink(contentsink);
 
   nsDTDMode mode = eDTDMode_autodetect;
   switch (document->GetCompatibilityMode()) {
     case eCompatibility_NavQuirks:
       mode = eDTDMode_quirks;
       break;
     case eCompatibility_AlmostStandards:
       mode = eDTDMode_almost_standards;
@@ -3432,16 +3464,18 @@ nsContentUtils::CreateContextualFragment
 
   // XXX Shouldn't we be returning rv if it's a failure code?
   rv = parser->ParseFragment(aFragment, nsnull, tagStack,
                              !bHTML, contentType, mode);
   if (NS_SUCCEEDED(rv)) {
     rv = sink->GetFragment(aReturn);
   }
 
+  document->SetFragmentParser(parser);
+
   return NS_OK;
 }
 
 /* static */
 nsresult
 nsContentUtils::CreateDocument(const nsAString& aNamespaceURI, 
                                const nsAString& aQualifiedName, 
                                nsIDOMDocumentType* aDoctype,
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -403,16 +403,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
                            &cb);
   }
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mImageMaps)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mImages)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mApplets)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mEmbeds)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLinks)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mAnchors)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFragmentParser)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mForms, nsIDOMNodeList)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mFormControls,
                                                        nsIDOMNodeList)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_ADDREF_INHERITED(nsHTMLDocument, nsDocument)
 NS_IMPL_RELEASE_INHERITED(nsHTMLDocument, nsDocument)
 
--- a/content/html/document/src/nsHTMLDocument.h
+++ b/content/html/document/src/nsHTMLDocument.h
@@ -211,16 +211,23 @@ public:
   {
     mDisableCookieAccess = PR_TRUE;
   }
 
   void EndUpdate(nsUpdateType aUpdateType);
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsHTMLDocument, nsDocument)
 
+  virtual already_AddRefed<nsIParser> GetFragmentParser() {
+    return mFragmentParser.forget();
+  }
+  virtual void SetFragmentParser(nsIParser* aParser) {
+    mFragmentParser = aParser;
+  }
+
 protected:
   nsresult GetBodySize(PRInt32* aWidth,
                        PRInt32* aHeight);
 
   nsresult RegisterNamedItems(nsIContent *aContent);
   nsresult UnregisterNamedItems(nsIContent *aContent);
   nsresult UpdateNameTableEntry(nsIAtom* aName, nsIContent *aContent);
   nsresult UpdateIdTableEntry(nsIAtom* aId, nsIContent *aContent);
@@ -377,11 +384,14 @@ protected:
 
   // kNameSpaceID_None for good ol' HTML documents, and
   // kNameSpaceID_XHTML for spiffy new XHTML documents.
   // XXXbz should this be reset if someone manually calls
   // SetContentType() on this document?
   PRInt32 mDefaultNamespaceID;
 
   PRBool mDisableCookieAccess;
+
+  // Parser used for constructing document fragments.
+  nsCOMPtr<nsIParser> mFragmentParser;
 };
 
 #endif /* nsHTMLDocument_h___ */
--- a/content/html/document/src/nsHTMLFragmentContentSink.cpp
+++ b/content/html/document/src/nsHTMLFragmentContentSink.cpp
@@ -59,32 +59,35 @@
 #include "nsContentUtils.h"
 #include "nsEscape.h"
 #include "nsNodeInfoManager.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsNetUtil.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsContentSink.h"
 #include "nsTHashtable.h"
+#include "nsCycleCollectionParticipant.h"
 
 //
 // XXX THIS IS TEMPORARY CODE
 // There's a considerable amount of copied code from the
 // regular nsHTMLContentSink. All of it will be factored
 // at some pointe really soon!
 //
 
 class nsHTMLFragmentContentSink : public nsIFragmentContentSink,
                                   public nsIHTMLContentSink {
 public:
   nsHTMLFragmentContentSink(PRBool aAllContent = PR_FALSE);
   virtual ~nsHTMLFragmentContentSink();
 
   // nsISupports
-  NS_DECL_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsHTMLFragmentContentSink,
+                                           nsIContentSink)
 
   NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
 
   // nsIContentSink
   NS_IMETHOD WillTokenize(void) { return NS_OK; }
   NS_IMETHOD WillBuildModel(void);
   NS_IMETHOD DidBuildModel(void);
   NS_IMETHOD WillInterrupt(void);
@@ -218,22 +221,32 @@ nsHTMLFragmentContentSink::~nsHTMLFragme
   PR_FREEIF(mText);
 
   PRUint32 i;
   for (i = 0; i < NS_ARRAY_LENGTH(mNodeInfoCache); ++i) {
     NS_IF_RELEASE(mNodeInfoCache[i]);
   }
 }
 
-NS_IMPL_ISUPPORTS3(nsHTMLFragmentContentSink,
-                   nsIFragmentContentSink,
-                   nsIHTMLContentSink,
-                   nsIContentSink)
+NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsHTMLFragmentContentSink,
+                                          nsIContentSink)
+NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsHTMLFragmentContentSink,
+                                           nsIContentSink)
 
-NS_IMETHODIMP 
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsHTMLFragmentContentSink)
+  NS_INTERFACE_MAP_ENTRY(nsIFragmentContentSink)
+  NS_INTERFACE_MAP_ENTRY(nsIHTMLContentSink)
+  NS_INTERFACE_MAP_ENTRY(nsIContentSink)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentSink)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTION_3(nsHTMLFragmentContentSink, mParser, mTargetDocument,
+                           mRoot)
+
+NS_IMETHODIMP
 nsHTMLFragmentContentSink::WillBuildModel(void)
 {
   if (mRoot) {
     return NS_OK;
   }
 
   NS_ASSERTION(mNodeInfoManager, "Need a nodeinfo manager!");
 
--- a/content/xml/document/src/nsXMLContentSink.cpp
+++ b/content/xml/document/src/nsXMLContentSink.cpp
@@ -180,25 +180,40 @@ nsXMLContentSink::Init(nsIDocument* aDoc
   mState = eXMLContentSinkState_InProlog;
   mDocElement = nsnull;
 
   MOZ_TIMER_DEBUGLOG(("Stop: nsXMLContentSink::Init()\n"));
   MOZ_TIMER_STOP(mWatch);
   return NS_OK;
 }
 
-NS_IMPL_ISUPPORTS_INHERITED7(nsXMLContentSink,
-                             nsContentSink,
-                             nsIContentSink,
-                             nsIXMLContentSink,
-                             nsIExpatSink,
-                             nsITimerCallback,
-                             nsIDocumentObserver,
-                             nsIMutationObserver,
-                             nsITransformObserver)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsXMLContentSink)
+  NS_INTERFACE_MAP_ENTRY(nsIContentSink)
+  NS_INTERFACE_MAP_ENTRY(nsIXMLContentSink)
+  NS_INTERFACE_MAP_ENTRY(nsIExpatSink)
+  NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
+  NS_INTERFACE_MAP_ENTRY(nsIDocumentObserver)
+  NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
+  NS_INTERFACE_MAP_ENTRY(nsITransformObserver)
+NS_INTERFACE_MAP_END_INHERITING(nsContentSink)
+
+NS_IMPL_ADDREF_INHERITED(nsXMLContentSink, nsContentSink)
+NS_IMPL_RELEASE_INHERITED(nsXMLContentSink, nsContentSink)
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLContentSink)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXMLContentSink,
+                                                  nsContentSink)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mCurrentHead)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mDocElement)
+  for (PRUint32 i = 0, count = tmp->mContentStack.Length(); i < count; i++) {
+    const StackNode& node = tmp->mContentStack.ElementAt(i);
+    cb.NoteXPCOMChild(node.mContent);
+  }
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 // nsIContentSink
 NS_IMETHODIMP
 nsXMLContentSink::WillTokenize(void)
 {
   return WillProcessTokensImpl();
 }
 
--- a/content/xml/document/src/nsXMLContentSink.h
+++ b/content/xml/document/src/nsXMLContentSink.h
@@ -40,17 +40,17 @@
 
 #include "nsContentSink.h"
 #include "nsIXMLContentSink.h"
 #include "nsIExpatSink.h"
 #include "nsIDocumentTransformer.h"
 #include "nsTArray.h"
 #include "nsCOMPtr.h"
 #include "nsCRT.h"
-
+#include "nsCycleCollectionParticipant.h"
 
 class nsIDocument;
 class nsIURI;
 class nsIContent;
 class nsINodeInfo;
 class nsIParser;
 class nsIViewManager;
 
@@ -79,16 +79,19 @@ public:
   nsresult Init(nsIDocument* aDoc,
                 nsIURI* aURL,
                 nsISupports* aContainer,
                 nsIChannel* aChannel);
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsXMLContentSink,
+                                                     nsContentSink)
+
   NS_DECL_NSIEXPATSINK
 
   // nsIContentSink
   NS_IMETHOD WillTokenize(void);
   NS_IMETHOD WillBuildModel(void);
   NS_IMETHOD DidBuildModel(void);
   NS_IMETHOD WillInterrupt(void);
   NS_IMETHOD WillResume(void);
--- a/content/xml/document/src/nsXMLFragmentContentSink.cpp
+++ b/content/xml/document/src/nsXMLFragmentContentSink.cpp
@@ -55,28 +55,31 @@
 #include "nsIScriptError.h"
 #include "nsServiceManagerUtils.h"
 #include "nsContentUtils.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsNetUtil.h"
 #include "nsTHashtable.h"
 #include "nsHashKeys.h"
 #include "nsTArray.h"
+#include "nsCycleCollectionParticipant.h"
 
 class nsXMLFragmentContentSink : public nsXMLContentSink,
                                  public nsIFragmentContentSink
 {
 public:
   nsXMLFragmentContentSink(PRBool aAllContent = PR_FALSE);
   virtual ~nsXMLFragmentContentSink();
 
   NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsXMLFragmentContentSink,
+                                                     nsXMLContentSink)
 
   // nsIExpatSink
   NS_IMETHOD HandleDoctypeDecl(const nsAString & aSubset, 
                                const nsAString & aName, 
                                const nsAString & aSystemId, 
                                const nsAString & aPublicId,
                                nsISupports* aCatalogData);
   NS_IMETHOD HandleProcessingInstruction(const PRUnichar *aTarget, 
@@ -164,19 +167,30 @@ nsXMLFragmentContentSink::nsXMLFragmentC
  : mParseError(PR_FALSE), mAllContent(aAllContent)
 {
 }
 
 nsXMLFragmentContentSink::~nsXMLFragmentContentSink()
 {
 }
 
-NS_IMPL_ISUPPORTS_INHERITED1(nsXMLFragmentContentSink,
-                             nsXMLContentSink,
-                             nsIFragmentContentSink)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsXMLFragmentContentSink)
+  NS_INTERFACE_MAP_ENTRY(nsIFragmentContentSink)
+NS_INTERFACE_MAP_END_INHERITING(nsXMLContentSink)
+
+NS_IMPL_ADDREF_INHERITED(nsXMLFragmentContentSink, nsXMLContentSink)
+NS_IMPL_RELEASE_INHERITED(nsXMLFragmentContentSink, nsXMLContentSink)
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLFragmentContentSink)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXMLFragmentContentSink,
+                                                  nsXMLContentSink)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTargetDocument)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mRoot)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMETHODIMP 
 nsXMLFragmentContentSink::WillBuildModel(void)
 {
   if (mRoot) {
     return NS_OK;
   }
 
--- a/parser/htmlparser/public/nsIParser.h
+++ b/parser/htmlparser/public/nsIParser.h
@@ -282,16 +282,18 @@ class nsIParser : public nsISupports {
      *  has been passed to the parser but the parser has been interrupted
      *  because processing the tokens took too long.
      *  
      *  @update  kmcclusk 05/18/01
      *  @return  NS_OK if succeeded else ERROR.
      */
 
     NS_IMETHOD CancelParsingEvents() = 0;
+
+    virtual void Reset() = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIParser, NS_IPARSER_IID)
 
 /* ===========================================================*
   Some useful constants...
  * ===========================================================*/
 
--- a/parser/htmlparser/src/CNavDTD.cpp
+++ b/parser/htmlparser/src/CNavDTD.cpp
@@ -108,21 +108,28 @@ static const  char kInvalidTagStackPos[]
 #define NS_DTD_FLAG_ALTERNATE_CONTENT      0x00000080 // NOFRAMES, NOSCRIPT
 #define NS_DTD_FLAG_MISPLACED_CONTENT      0x00000100
 #define NS_DTD_FLAG_IN_MISPLACED_CONTENT   0x00000200
 #define NS_DTD_FLAG_STOP_PARSING           0x00000400
 
 #define NS_DTD_FLAG_HAS_MAIN_CONTAINER     (NS_DTD_FLAG_HAD_BODY |            \
                                             NS_DTD_FLAG_HAD_FRAMESET)
 
-NS_IMPL_ISUPPORTS1(CNavDTD, nsIDTD)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CNavDTD)
+  NS_INTERFACE_MAP_ENTRY(nsIDTD)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDTD)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(CNavDTD)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(CNavDTD)
+
+NS_IMPL_CYCLE_COLLECTION_1(CNavDTD, mSink)
 
 CNavDTD::CNavDTD()
   : mMisplacedContent(0),
-    mSink(0),
     mTokenAllocator(0),
     mBodyContext(new nsDTDContext()),
     mTempContext(0),
     mParser(0),
     mTokenizer(0),
     mDTDMode(eDTDMode_quirks),
     mDocType(eHTML3_Quirks), // why not eHTML_Quirks?
     mParserCommand(eViewNormal),
@@ -176,18 +183,16 @@ CNavDTD::~CNavDTD()
 #ifdef NS_DEBUG
   if (mSink) {
     nsLoggingSink *theLogSink = GetLoggingSink();
     if (mSink == theLogSink) {
       theLogSink->ReleaseProxySink();
     }
   }
 #endif
-
-  NS_IF_RELEASE(mSink);
 }
 
 nsresult
 CNavDTD::WillBuildModel(const CParserContext& aParserContext,
                         nsITokenizer* aTokenizer,
                         nsIContentSink* aSink)
 {
   nsresult result = NS_OK;
@@ -207,17 +212,17 @@ CNavDTD::WillBuildModel(const CParserCon
     MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::WillBuildModel(), this=%p\n", this));
     
     result = aSink->WillBuildModel();
     
     MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::WillBuildModel(), this=%p\n", this));
     START_TIMER();
 
     if (NS_SUCCEEDED(result) && !mSink) {
-      result = CallQueryInterface(aSink, &mSink);
+      mSink = do_QueryInterface(aSink, &result);
       if (NS_FAILED(result)) {
         mFlags |= NS_DTD_FLAG_STOP_PARSING;
         return result;
       }
     }
     
     // Let's see if the environment is set up for us to write output to
     // a logging sink. If so, then we'll create one, and make it the
--- a/parser/htmlparser/src/CNavDTD.h
+++ b/parser/htmlparser/src/CNavDTD.h
@@ -101,16 +101,17 @@
 #include "nsIParser.h"
 #include "nsHTMLTags.h"
 #include "nsVoidArray.h"
 #include "nsDeque.h"
 #include "nsParserCIID.h"
 #include "nsTime.h"
 #include "nsDTDUtils.h"
 #include "nsParser.h"
+#include "nsCycleCollectionParticipant.h"
 
 class nsIHTMLContentSink;
 class nsIParserNode;
 class nsDTDContext;
 class nsEntryStack;
 class nsITokenizer;
 class nsCParserNode;
 class nsTokenAllocator;
@@ -153,18 +154,19 @@ public:
      *             aNode.
      * @param aStyleStack The style stack that aNode might be a member of
      *                    (usually null).
      */
     nsresult OpenContainer(const nsCParserNode *aNode,
                            eHTMLTags aTag,
                            nsEntryStack* aStyleStack = nsnull);
 
-    NS_DECL_ISUPPORTS
+    NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_NSIDTD
+    NS_DECL_CYCLE_COLLECTION_CLASS(CNavDTD)
 
 private:
     /**
      *  This method is called to determine whether or not a tag
      *  of one type can contain a tag of another type.
      *  
      *  @param   aParent Tag of parent container
      *  @param   aChild Tag of child container
@@ -376,17 +378,17 @@ protected:
       NS_ASSERTION(mParser && mParser->PeekContext(),
                    "Parser must be parsing to use this function");
 
       return mParser->PeekContext()->mPrevContext != nsnull;
     }
     
     nsDeque             mMisplacedContent;
     
-    nsIHTMLContentSink* mSink;
+    nsCOMPtr<nsIHTMLContentSink> mSink;
     nsTokenAllocator*   mTokenAllocator;
     nsDTDContext*       mBodyContext;
     nsDTDContext*       mTempContext;
     nsParser*           mParser;
     nsITokenizer*       mTokenizer; // weak
    
     nsString            mFilename; 
     nsString            mScratch;  //used for various purposes; non-persistent
--- a/parser/htmlparser/src/nsExpatDriver.cpp
+++ b/parser/htmlparser/src/nsExpatDriver.cpp
@@ -373,19 +373,26 @@ IsLoadableDTD(const nsCatalogData* aCata
   // Set aDTD to a file: url pointing to the local DTD
   NS_NewFileURI(aResult, dtdPath);
 
   return *aResult != nsnull;
 }
 
 /***************************** END CATALOG UTILS *****************************/
 
-NS_IMPL_ISUPPORTS2(nsExpatDriver,
-                   nsITokenizer,
-                   nsIDTD)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsExpatDriver)
+  NS_INTERFACE_MAP_ENTRY(nsITokenizer)
+  NS_INTERFACE_MAP_ENTRY(nsIDTD)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDTD)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsExpatDriver)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(nsExpatDriver)
+
+NS_IMPL_CYCLE_COLLECTION_2(nsExpatDriver, mSink, mExtendedSink)
 
 nsExpatDriver::nsExpatDriver()
   : mExpatParser(nsnull),
     mInCData(PR_FALSE),
     mInInternalSubset(PR_FALSE),
     mInExternalDTD(PR_FALSE),
     mIsFinalChunk(PR_FALSE),
     mInternalState(NS_OK),
--- a/parser/htmlparser/src/nsExpatDriver.h
+++ b/parser/htmlparser/src/nsExpatDriver.h
@@ -41,28 +41,30 @@
 #include "expat_config.h"
 #include "expat.h"
 #include "nsCOMPtr.h"
 #include "nsString.h"
 #include "nsIDTD.h"
 #include "nsITokenizer.h"
 #include "nsIInputStream.h"
 #include "nsIParser.h"
+#include "nsCycleCollectionParticipant.h"
 
 class nsIExpatSink;
 class nsIExtendedExpatSink;
 struct nsCatalogData;
 
 class nsExpatDriver : public nsIDTD,
                       public nsITokenizer
 {
 public:
-  NS_DECL_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_NSIDTD
   NS_DECL_NSITOKENIZER
+  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsExpatDriver, nsIDTD)
 
   nsExpatDriver();
   virtual ~nsExpatDriver();
 
   int HandleExternalEntityRef(const PRUnichar *aOpenEntityNames,
                               const PRUnichar *aBase,
                               const PRUnichar *aSystemId,
                               const PRUnichar *aPublicId);
--- a/parser/htmlparser/src/nsParser.cpp
+++ b/parser/htmlparser/src/nsParser.cpp
@@ -240,45 +240,62 @@ void nsParser::Shutdown()
 static PRBool gDumpContent=PR_FALSE;
 #endif
 
 /**
  *  default constructor
  */
 nsParser::nsParser()
 {
+  Initialize(PR_TRUE);
+}
+
+nsParser::~nsParser()
+{
+  Cleanup();
+}
+
+void
+nsParser::Initialize(PRBool aConstructor)
+{
 #ifdef NS_DEBUG
   if (!gDumpContent) {
     gDumpContent = PR_GetEnv("PARSER_DUMP_CONTENT") != nsnull;
   }
 #endif
 
+  if (aConstructor) {
+    // Raw pointer
+    mParserContext = 0;
+  }
+  else {
+    // nsCOMPtrs
+    mObserver = nsnull;
+    mParserFilter = nsnull;
+  }
+
+  mContinueEvent = nsnull;
+  mCharsetSource = kCharsetUninitialized;
   mCharset.AssignLiteral("ISO-8859-1");
-  mParserContext=0;
-  mStreamStatus=0;
-  mCharsetSource=kCharsetUninitialized;
-  mInternalState=NS_OK;
-  mContinueEvent=nsnull;
-  mCommand=eViewNormal;
+  mInternalState = NS_OK;
+  mStreamStatus = 0;
+  mCommand = eViewNormal;
   mFlags = NS_PARSER_FLAG_OBSERVERS_ENABLED |
            NS_PARSER_FLAG_PARSER_ENABLED |
            NS_PARSER_FLAG_CAN_TOKENIZE;
 
   MOZ_TIMER_DEBUGLOG(("Reset: Parse Time: nsParser::nsParser(), this=%p\n", this));
   MOZ_TIMER_RESET(mParseTime);
   MOZ_TIMER_RESET(mDTDTime);
   MOZ_TIMER_RESET(mTokenizeTime);
 }
 
-/**
- *  Destructor
- */
-nsParser::~nsParser()
+void
+nsParser::Cleanup()
 {
-
 #ifdef NS_DEBUG
   if (gDumpContent) {
     if (mSink) {
       // Sink (HTMLContentSink at this time) supports nsIDebugDumpContent
       // interface. We can get to the content model through the sink.
       nsresult result = NS_OK;
       nsCOMPtr<nsIDebugDumpContent> trigger = do_QueryInterface(mSink, &result);
       if (NS_SUCCEEDED(result)) {
@@ -301,24 +318,41 @@ nsParser::~nsParser()
   }
 
   // It should not be possible for this flag to be set when we are getting
   // destroyed since this flag implies a pending nsParserContinueEvent, which
   // has an owning reference to |this|.
   NS_ASSERTION(!(mFlags & NS_PARSER_FLAG_PENDING_CONTINUE_EVENT), "bad");
 }
 
-NS_IMPL_CYCLE_COLLECTION_2(nsParser, mSink, mObserver)
+NS_IMPL_CYCLE_COLLECTION_CLASS(nsParser)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsParser)
+  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(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)
- NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
- NS_INTERFACE_MAP_ENTRY(nsIParser)
- NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
- NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIParser)
+  NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
+  NS_INTERFACE_MAP_ENTRY(nsIParser)
+  NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIParser)
 NS_INTERFACE_MAP_END
 
 // The parser continue event is posted only if
 // all of the data to parse has been passed to ::OnDataAvailable
 // and the parser has been interrupted by the content sink
 // because the processing of tokens took too long.
 
 nsresult
--- a/parser/htmlparser/src/nsParser.h
+++ b/parser/htmlparser/src/nsParser.h
@@ -376,17 +376,25 @@ class nsParser : public nsIParser,
     static nsICharsetAlias* GetCharsetAliasService() {
       return sCharsetAliasService;
     }
 
     static nsICharsetConverterManager* GetCharsetConverterManager() {
       return sCharsetConverterManager;
     }
 
-protected:
+    virtual void Reset() {
+      Cleanup();
+      Initialize();
+    }
+
+ protected:
+
+    void Initialize(PRBool aConstructor = PR_FALSE);
+    void Cleanup();
 
     /**
      * 
      * @update	gess5/18/98
      * @param 
      * @return
      */
     nsresult WillBuildModel(nsString& aFilename);