Bug 579764: Send out notification when the document-element for a document has been created and inserted into the DOM. r=jst a=blocker
authorJonas Sicking <jonas@sicking.cc>
Fri, 27 Aug 2010 22:54:57 -0700
changeset 51669 34afbe32fb0e2386509d1880fc45dd5dce95aab9
parent 51668 1fe5a5c22b0fac3b770797543c3052e654728670
child 51670 a237bc7080ab96b5d8ec00a30e3c1ad576ea1610
push idunknown
push userunknown
push dateunknown
reviewersjst, blocker
bugs579764
milestone2.0b5pre
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 579764: Send out notification when the document-element for a document has been created and inserted into the DOM. r=jst a=blocker
content/base/src/nsContentSink.cpp
content/base/src/nsContentSink.h
content/xml/document/src/nsXMLContentSink.cpp
content/xslt/src/xslt/txMozillaXMLOutput.cpp
parser/html/nsHtml5TreeOperation.cpp
--- a/content/base/src/nsContentSink.cpp
+++ b/content/base/src/nsContentSink.cpp
@@ -1693,16 +1693,30 @@ void
 nsContentSink::ContinueInterruptedParsingAsync()
 {
   nsCOMPtr<nsIRunnable> ev = NS_NewRunnableMethod(this,
     &nsContentSink::ContinueInterruptedParsingIfEnabled);
 
   NS_DispatchToCurrentThread(ev);
 }
 
+/* static */
+void
+nsContentSink::NotifyDocElementCreated(nsIDocument* aDoc)
+{
+  nsCOMPtr<nsIObserverService> observerService =
+    mozilla::services::GetObserverService();
+  if (observerService) {
+    nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aDoc);
+    observerService->
+      NotifyObservers(domDoc, "document-element-inserted",
+                      EmptyString().get());
+  }
+}
+
 // URIs: action, href, src, longdesc, usemap, cite
 PRBool 
 IsAttrURI(nsIAtom *aName)
 {
   return (aName == nsGkAtoms::action ||
           aName == nsGkAtoms::href ||
           aName == nsGkAtoms::src ||
           aName == nsGkAtoms::longdesc ||
--- a/content/base/src/nsContentSink.h
+++ b/content/base/src/nsContentSink.h
@@ -265,16 +265,19 @@ protected:
   // done that, further calls to this method will be ignored.
   void ScrollToRef();
 
   // 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.
 public:
   void StartLayout(PRBool aIgnorePendingSheets);
+
+  static void NotifyDocElementCreated(nsIDocument* aDoc);
+
 protected:
   void
   FavorPerformanceHint(PRBool perfOverStarvation, PRUint32 starvationDelay);
 
   inline PRInt32 GetNotificationInterval()
   {
     if (mDynamicLowerValue) {
       return 1000;
--- a/content/xml/document/src/nsXMLContentSink.cpp
+++ b/content/xml/document/src/nsXMLContentSink.cpp
@@ -441,17 +441,17 @@ nsXMLContentSink::OnTransformDone(nsresu
   if (rootElement) {
     NS_ASSERTION(mDocument->IndexOf(rootElement) != -1,
                  "rootElement not in doc?");
     mDocument->BeginUpdate(UPDATE_CONTENT_MODEL);
     nsNodeUtils::ContentInserted(mDocument, rootElement,
                                  mDocument->IndexOf(rootElement));
     mDocument->EndUpdate(UPDATE_CONTENT_MODEL);
   }
-  
+
   // Start the layout process
   StartLayout(PR_FALSE);
 
   ScrollToRef();
 
   originalDocument->EndLoad();
 
   return NS_OK;
@@ -1083,16 +1083,20 @@ nsXMLContentSink::HandleStartElement(con
   }
 
   if (content != mDocElement && !mCurrentHead) {
     // This isn't the root and we're not inside an XHTML <head>.
     // Might need to start layout
     MaybeStartLayout(PR_FALSE);
   }
 
+  if (content == mDocElement) {
+    NotifyDocElementCreated(mDocument);
+  }
+
   return aInterruptable && NS_SUCCEEDED(result) ? DidProcessATokenImpl() :
                                                   result;
 }
 
 NS_IMETHODIMP
 nsXMLContentSink::HandleEndElement(const PRUnichar *aName)
 {
   return HandleEndElement(aName, PR_TRUE);
--- a/content/xslt/src/xslt/txMozillaXMLOutput.cpp
+++ b/content/xslt/src/xslt/txMozillaXMLOutput.cpp
@@ -63,16 +63,17 @@
 #include "nsIHTMLDocument.h"
 #include "nsIStyleSheetLinkingElement.h"
 #include "nsIDocumentTransformer.h"
 #include "mozilla/css/Loader.h"
 #include "nsICharsetAlias.h"
 #include "nsIHTMLContentSink.h"
 #include "nsContentUtils.h"
 #include "txXMLUtils.h"
+#include "nsContentSink.h"
 #include "nsINode.h"
 #include "nsContentCreatorFunctions.h"
 #include "txError.h"
 
 #define TX_ENSURE_CURRENTNODE                           \
     NS_ASSERTION(mCurrentNode, "mCurrentNode is NULL"); \
     if (!mCurrentNode)                                  \
         return NS_ERROR_UNEXPECTED
@@ -572,23 +573,24 @@ txMozillaXMLOutput::closePrevious(PRBool
             // We already have a document element, but the XSLT spec allows this.
             // As a workaround, create a wrapper object and use that as the
             // document element.
             
             rv = createTxWrapper();
             NS_ENSURE_SUCCESS(rv, rv);
         }
 
+        rv = mCurrentNode->AppendChildTo(mOpenedElement, PR_TRUE);
+        NS_ENSURE_SUCCESS(rv, rv);
+
         if (currentIsDoc) {
             mRootContentCreated = PR_TRUE;
+            nsContentSink::NotifyDocElementCreated(mDocument);
         }
 
-        rv = mCurrentNode->AppendChildTo(mOpenedElement, PR_TRUE);
-        NS_ENSURE_SUCCESS(rv, rv);
-
         mCurrentNode = mOpenedElement;
         mOpenedElement = nsnull;
     }
     else if (aFlushText && !mText.IsEmpty()) {
         // Text can't appear in the root of a document
         if (mDocument == mCurrentNode) {
             if (XMLUtils::isWhitespace(mText)) {
                 mText.Truncate();
--- a/parser/html/nsHtml5TreeOperation.cpp
+++ b/parser/html/nsHtml5TreeOperation.cpp
@@ -52,16 +52,18 @@
 #include "nsContentCreatorFunctions.h"
 #include "nsIScriptElement.h"
 #include "nsIDTD.h"
 #include "nsTraceRefcnt.h"
 #include "nsIDOMHTMLFormElement.h"
 #include "nsIFormControl.h"
 #include "nsIStyleSheetLinkingElement.h"
 #include "nsIDOMDocumentType.h"
+#include "nsIObserverService.h"
+#include "mozilla/Services.h"
 #include "nsIMutationObserver.h"
 #include "nsIFormProcessor.h"
 #include "nsIServiceManager.h"
 #include "nsEscape.h"
 #include "mozilla/dom/Element.h"
 
 #ifdef MOZ_SVG
 #include "nsHtml5SVGLoadDispatcher.h"
@@ -222,27 +224,50 @@ nsHtml5TreeOperation::Append(nsIContent*
   PRUint32 childCount = aParent->GetChildCount();
   rv = aParent->AppendChildTo(aNode, PR_FALSE);
   nsNodeUtils::ContentAppended(aParent, aNode, childCount);
 
   parentDoc->EndUpdate(UPDATE_CONTENT_MODEL);
   return rv;
 }
 
+class nsDocElementCreatedNotificationRunner : public nsRunnable
+{
+public:
+  nsDocElementCreatedNotificationRunner(nsIDocument* aDoc)
+    : mDoc(aDoc)
+  {
+  }
+
+  NS_IMETHOD Run()
+  {
+    nsContentSink::NotifyDocElementCreated(mDoc);
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsIDocument> mDoc;
+};
+
 nsresult
 nsHtml5TreeOperation::AppendToDocument(nsIContent* aNode,
                                        nsHtml5TreeOpExecutor* aBuilder)
 {
   nsresult rv = NS_OK;
   aBuilder->FlushPendingAppendNotifications();
   nsIDocument* doc = aBuilder->GetDocument();
   PRUint32 childCount = doc->GetChildCount();
   rv = doc->AppendChildTo(aNode, PR_FALSE);
   NS_ENSURE_SUCCESS(rv, rv);
   nsNodeUtils::ContentInserted(doc, aNode, childCount);
+
+  NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
+               "Someone forgot to block scripts");
+  nsContentUtils::AddScriptRunner(
+    new nsDocElementCreatedNotificationRunner(doc));
+
   return rv;
 }
 
 nsresult
 nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder,
                               nsIContent** aScriptElement)
 {
   nsresult rv = NS_OK;