Bug 677658, disable scriptloader when parsing in innerHTML/InsertAdjacentHTML, r=sicking
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Wed, 10 Aug 2011 23:53:14 +0300
changeset 74190 3bf55a9e34e8f6e86372c19b4881da49a88cd5bc
parent 74189 52c4a8829da3fa4452fba03ffc3e8233988324dd
child 74191 89a9f4a88d5be96eea417062a77da95a0e8d5c77
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
reviewerssicking
bugs677658
milestone8.0a1
Bug 677658, disable scriptloader when parsing in innerHTML/InsertAdjacentHTML, r=sicking
content/base/src/nsScriptLoader.h
content/html/content/src/nsGenericHTMLElement.cpp
content/html/content/test/Makefile.in
content/html/content/test/test_bug677658.html
--- a/content/base/src/nsScriptLoader.h
+++ b/content/base/src/nsScriptLoader.h
@@ -331,9 +331,32 @@ private:
   // XXXbz do we want to cycle-collect these or something?  Not sure.
   nsTArray< nsRefPtr<nsScriptLoader> > mPendingChildLoaders;
   PRUint32 mBlockerCount;
   PRPackedBool mEnabled;
   PRPackedBool mDeferEnabled;
   PRPackedBool mDocumentParsingDone;
 };
 
+class nsAutoScriptLoaderDisabler
+{
+public:
+  nsAutoScriptLoaderDisabler(nsIDocument* aDoc)
+  {
+    mLoader = aDoc->ScriptLoader();
+    mWasEnabled = mLoader->GetEnabled();
+    if (mWasEnabled) {
+      mLoader->SetEnabled(PR_FALSE);
+    }
+  }
+  
+  ~nsAutoScriptLoaderDisabler()
+  {
+    if (mWasEnabled) {
+      mLoader->SetEnabled(PR_TRUE);
+    }
+  }
+  
+  PRBool mWasEnabled;
+  nsRefPtr<nsScriptLoader> mLoader;
+};
+
 #endif //__nsScriptLoader_h__
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -760,16 +760,18 @@ nsGenericHTMLElement::SetInnerHTML(const
   mozAutoDocUpdate updateBatch(doc, UPDATE_CONTENT_MODEL, PR_TRUE);
 
   // Remove childnodes.
   PRUint32 childCount = GetChildCount();
   for (PRUint32 i = 0; i < childCount; ++i) {
     RemoveChildAt(0, PR_TRUE);
   }
 
+  nsAutoScriptLoaderDisabler sld(doc);
+  
   nsCOMPtr<nsIDOMDocumentFragment> df;
 
   if (doc->IsHTML()) {
     PRInt32 oldChildCount = GetChildCount();
     nsContentUtils::ParseFragmentHTML(aInnerHTML,
                                       this,
                                       Tag(),
                                       GetNameSpaceID(),
@@ -823,27 +825,28 @@ nsGenericHTMLElement::InsertAdjacentHTML
     }
   } else {
     destination = this;
   }
 
   nsIDocument* doc = GetOwnerDoc();
   NS_ENSURE_STATE(doc);
 
+  // Needed when insertAdjacentHTML is used in combination with contenteditable
+  mozAutoDocUpdate updateBatch(doc, UPDATE_CONTENT_MODEL, PR_TRUE);
+  nsAutoScriptLoaderDisabler sld(doc);
+  
   // Batch possible DOMSubtreeModified events.
   mozAutoSubtreeModified subtree(doc, nsnull);
 
   // Parse directly into destination if possible
   if (doc->IsHTML() &&
       (position == eBeforeEnd ||
        (position == eAfterEnd && !GetNextSibling()) ||
        (position == eAfterBegin && !GetFirstChild()))) {
-    // Needed when insertAdjacentHTML is used in combination with contenteditable
-    mozAutoDocUpdate updateBatch(doc, UPDATE_CONTENT_MODEL, PR_TRUE);
-
     PRInt32 oldChildCount = destination->GetChildCount();
     PRInt32 contextNs = destination->GetNameSpaceID();
     nsIAtom* contextLocal = destination->Tag();
     if (contextLocal == nsGkAtoms::html && contextNs == kNameSpaceID_XHTML) {
       // For compat with IE6 through IE9. Willful violation of HTML5 as of
       // 2011-04-06. CreateContextualFragment does the same already.
       // Spec bug: http://www.w3.org/Bugs/Public/show_bug.cgi?id=12434
       contextLocal = nsGkAtoms::body;
@@ -864,16 +867,21 @@ nsGenericHTMLElement::InsertAdjacentHTML
   nsCOMPtr<nsIDOMDocumentFragment> df;
   nsresult rv = nsContentUtils::CreateContextualFragment(destination,
                                                          aText,
                                                          PR_TRUE,
                                                          getter_AddRefs(df));
   nsCOMPtr<nsINode> fragment = do_QueryInterface(df);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  // Suppress assertion about node removal mutation events that can't have
+  // listeners anyway, because no one has had the chance to register mutation
+  // listeners on the fragment that comes from the parser.
+  nsAutoScriptBlockerSuppressNodeRemoved scriptBlocker;
+
   switch (position) {
     case eBeforeBegin:
       destination->InsertBefore(fragment, this, &rv);
       break;
     case eAfterBegin:
       static_cast<nsINode*>(this)->InsertBefore(fragment, GetFirstChild(), &rv);
       break;
     case eBeforeEnd:
--- a/content/html/content/test/Makefile.in
+++ b/content/html/content/test/Makefile.in
@@ -276,12 +276,13 @@ include $(topsrcdir)/config/rules.mk
 		test_bug664299.html \
 		test_bug666200.html \
 		test_bug666666.html \
 		test_bug674558.html \
 		test_bug583533.html \
 		test_restore_from_parser_fragment.html \
 		test_bug617528.html \
 		test_checked.html \
+		test_bug677658.html \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/test_bug677658.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=677658
+-->
+<head>
+  <title>Test for Bug 677658</title>
+  <script type="application/javascript" src="/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body onload="test()">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=677658">Mozilla Bug 677658</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script type="application/javascript"><!--
+
+/** Test for Bug 677658 **/
+
+SimpleTest.waitForExplicitFinish();
+
+function testDone() {
+  ok(window.testPassed, "Script shouldn't have run!");
+  SimpleTest.finish();
+}
+
+function test() {
+  window.testPassed = true;
+  document.getElementById("testtarget").innerHTML =
+    "<script async src='data:text/plain, window.testPassed = false;'></script>";
+  SimpleTest.executeSoon(testDone);
+}
+
+// -->
+</script>
+</pre>
+<div id="testtarget"></div>
+</body>
+</html>