Bug 1455680 - Notify document-element-inserted in XUL documents;r=bz
authorBrian Grinstead <bgrinstead@mozilla.com>
Fri, 20 Apr 2018 13:55:51 -0700
changeset 468339 427e3dce92c2eec8fa9a167fef3f2a726b4010a6
parent 468338 85d1752bed2ed20849993ae3669157cbd42a3ed8
child 468340 42f5c08a4d86967ccd3df66c3fc3c30cc52c6497
push id9165
push userasasaki@mozilla.com
push dateThu, 26 Apr 2018 21:04:54 +0000
treeherdermozilla-beta@064c3804de2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs1455680
milestone61.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 1455680 - Notify document-element-inserted in XUL documents;r=bz We'll want to use this event to inject scripts before other scripts run in XUL documents. It already fires in HTML documents. MozReview-Commit-ID: 7FW0R8r9o9G
dom/base/nsContentSink.cpp
dom/base/test/chrome/chrome.ini
dom/base/test/chrome/file_document-element-inserted-inner.xul
dom/base/test/chrome/file_document-element-inserted.xul
dom/base/test/chrome/test_document-element-inserted.xul
dom/xml/nsXMLContentSink.cpp
dom/xslt/xslt/txMozillaXMLOutput.cpp
dom/xul/XULDocument.cpp
--- a/dom/base/nsContentSink.cpp
+++ b/dom/base/nsContentSink.cpp
@@ -1640,16 +1640,18 @@ nsContentSink::WillBuildModelImpl()
     DoProcessLinkHeader();
   }
 }
 
 /* static */
 void
 nsContentSink::NotifyDocElementCreated(nsIDocument* aDoc)
 {
+  MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
+
   nsCOMPtr<nsIObserverService> observerService =
     mozilla::services::GetObserverService();
   if (observerService) {
     nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aDoc);
     observerService->
       NotifyObservers(domDoc, "document-element-inserted",
                       EmptyString().get());
   }
--- a/dom/base/test/chrome/chrome.ini
+++ b/dom/base/test/chrome/chrome.ini
@@ -60,16 +60,20 @@ support-files = ../file_bug357450.js
 [test_bug1063837.xul]
 [test_bug1139964.xul]
 [test_bug1209621.xul]
 [test_bug1346936.html]
 [test_cpows.xul]
 [test_getElementsWithGrid.html]
 [test_custom_element_content.xul]
 [test_custom_element_ep.xul]
+[test_document-element-inserted.xul]
+support-files =
+  file_document-element-inserted.xul
+  file_document-element-inserted-inner.xul
 [test_domparsing.xul]
 [test_fileconstructor.xul]
 [test_nsITextInputProcessor.xul]
 [test_node_localize.xul]
 [test_permission_isHandlingUserInput.xul]
 support-files = ../dummy.html
 [test_range_getClientRectsAndTexts.html]
 [test_title.xul]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/chrome/file_document-element-inserted-inner.xul
@@ -0,0 +1,1 @@
+<window xmlns='http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul'></window>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/base/test/chrome/file_document-element-inserted.xul
@@ -0,0 +1,3 @@
+<window xmlns='http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul'>
+  <iframe src='file_document-element-inserted-inner.xul'></iframe>
+</window>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/base/test/chrome/test_document-element-inserted.xul
@@ -0,0 +1,55 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+                 type="text/css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1411707
+-->
+<window title="Mozilla Bug 1411707"
+  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+  <!-- test results are displayed in the html:body -->
+  <body xmlns="http://www.w3.org/1999/xhtml">
+  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1411707"
+     target="_blank">Mozilla Bug 1411707</a>
+  </body>
+
+  <!-- test code goes here -->
+  <script type="application/javascript"><![CDATA[
+    SimpleTest.waitForExplicitFinish();
+
+    const OUTER_URL = "chrome://mochitests/content/chrome/dom/base/test/chrome/file_document-element-inserted.xul";
+    const INNER_URL = "chrome://mochitests/content/chrome/dom/base/test/chrome/file_document-element-inserted-inner.xul";
+
+    async function waitForEvent(url) {
+      return new Promise(resolve => {
+        SpecialPowers.addObserver(function inserted(document) {
+          is(document.documentURI, url, "Correct URL");
+          is(document.readyState, "uninitialized", "Correct readyState");
+          SpecialPowers.removeObserver(inserted, "document-element-inserted");
+          resolve();
+        }, "document-element-inserted");
+      })
+    }
+
+    // Load a XUL document that also has an iframe to a subdocument, and
+    // expect both events to fire with the docs in the correct state.
+    async function testEvents() {
+      info(`Waiting for events after loading ${OUTER_URL}`);
+      let win = window.openDialog(OUTER_URL, null, "chrome,dialog=no,all");
+      await waitForEvent(OUTER_URL);
+      await waitForEvent(INNER_URL);
+      win.close();
+    }
+
+    (async function() {
+      // Test the same document twice to make to make sure we are
+      // firing properly when loading the protype document.
+      await testEvents();
+      await testEvents();
+      SimpleTest.finish();
+    })();
+  ]]></script>
+</window>
--- a/dom/xml/nsXMLContentSink.cpp
+++ b/dom/xml/nsXMLContentSink.cpp
@@ -14,16 +14,17 @@
 #include "nsIDocShell.h"
 #include "nsIStyleSheetLinkingElement.h"
 #include "nsHTMLParts.h"
 #include "nsCRT.h"
 #include "mozilla/StyleSheetInlines.h"
 #include "mozilla/css/Loader.h"
 #include "nsGkAtoms.h"
 #include "nsContentUtils.h"
+#include "nsDocElementCreatedNotificationRunner.h"
 #include "nsIScriptContext.h"
 #include "nsNameSpaceManager.h"
 #include "nsIServiceManager.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIContentViewer.h"
 #include "prtime.h"
 #include "mozilla/Logging.h"
 #include "nsRect.h"
@@ -1045,17 +1046,18 @@ nsXMLContentSink::HandleStartElement(con
   }
 
   if (IsMonolithicContainer(nodeInfo)) {
     mInMonolithicContainer++;
   }
 
   if (!mXSLTProcessor) {
     if (content == mDocElement) {
-      NotifyDocElementCreated(mDocument);
+      nsContentUtils::AddScriptRunner(
+          new nsDocElementCreatedNotificationRunner(mDocument));
 
       if (aInterruptable && NS_SUCCEEDED(result) && mParser && !mParser->IsParserEnabled()) {
         return NS_ERROR_HTMLPARSER_BLOCK;
       }
     } else if (!mCurrentHead) {
       // This isn't the root and we're not inside an XHTML <head>.
       // Might need to start layout
       MaybeStartLayout(false);
--- a/dom/xslt/xslt/txMozillaXMLOutput.cpp
+++ b/dom/xslt/xslt/txMozillaXMLOutput.cpp
@@ -27,16 +27,17 @@
 #include "mozilla/StyleSheetInlines.h"
 #include "mozilla/css/Loader.h"
 #include "mozilla/dom/DocumentType.h"
 #include "mozilla/dom/DocumentFragment.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/ScriptLoader.h"
 #include "mozilla/Encoding.h"
 #include "nsContentUtils.h"
+#include "nsDocElementCreatedNotificationRunner.h"
 #include "txXMLUtils.h"
 #include "nsContentSink.h"
 #include "nsINode.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsError.h"
 #include "nsIFrame.h"
 #include <algorithm>
 #include "nsTextNode.h"
@@ -573,17 +574,18 @@ txMozillaXMLOutput::closePrevious(bool a
             NS_ENSURE_SUCCESS(rv, rv);
         }
 
         rv = mCurrentNode->AppendChildTo(mOpenedElement, true);
         NS_ENSURE_SUCCESS(rv, rv);
 
         if (currentIsDoc) {
             mRootContentCreated = true;
-            nsContentSink::NotifyDocElementCreated(mDocument);
+            nsContentUtils::AddScriptRunner(
+                  new nsDocElementCreatedNotificationRunner(mDocument));
         }
 
         mCurrentNode = mOpenedElement;
         mOpenedElement = nullptr;
     }
     else if (aFlushText && !mText.IsEmpty()) {
         // Text can't appear in the root of a document
         if (mDocument == mCurrentNode) {
--- a/dom/xul/XULDocument.cpp
+++ b/dom/xul/XULDocument.cpp
@@ -35,16 +35,17 @@
 #include "nsITimer.h"
 #include "nsDocShell.h"
 #include "nsGkAtoms.h"
 #include "nsXMLContentSink.h"
 #include "nsXULContentSink.h"
 #include "nsXULContentUtils.h"
 #include "nsIXULOverlayProvider.h"
 #include "nsIStringEnumerator.h"
+#include "nsDocElementCreatedNotificationRunner.h"
 #include "nsNetUtil.h"
 #include "nsParserCIID.h"
 #include "nsPIBoxObject.h"
 #include "mozilla/dom/BoxObject.h"
 #include "nsString.h"
 #include "nsPIDOMWindow.h"
 #include "nsPIWindowRoot.h"
 #include "nsXULCommandDispatcher.h"
@@ -2021,16 +2022,19 @@ XULDocument::PrepareToWalk()
         if (NS_FAILED(rv)) return rv;
 
         rv = AppendChildTo(root, false);
         if (NS_FAILED(rv)) return rv;
 
         // Block onload until we've finished building the complete
         // document content model.
         BlockOnload();
+
+        nsContentUtils::AddScriptRunner(
+            new nsDocElementCreatedNotificationRunner(this));
     }
 
     // There'd better not be anything on the context stack at this
     // point! This is the basis case for our "induction" in
     // ResumeWalk(), below, which'll assume that there's always a
     // content element on the context stack if either 1) we're in the
     // "master" document, or 2) we're in an overlay, and we've got
     // more than one prototype element (the single, root "overlay"