Bug 602838 part 2 - Make script-created scripts (incl. scripts that have lost their parser-insertedness) default to .async=true. r=jonas, a=blocking2.0-beta8.
authorHenri Sivonen <hsivonen@iki.fi>
Wed, 27 Oct 2010 15:04:09 +0300
changeset 57322 be59b0a650ad
parent 57321 fce2fc592595
child 57323 834612a39147
push id16873
push userhsivonen@iki.fi
push date2010-11-11 07:53 +0000
treeherdermozilla-central@be59b0a650ad [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjonas, blocking2
bugs602838
milestone2.0b8pre
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 602838 part 2 - Make script-created scripts (incl. scripts that have lost their parser-insertedness) default to .async=true. r=jonas, a=blocking2.0-beta8.
content/base/public/nsIScriptElement.h
content/base/test/test_bug602838.html
content/html/content/src/nsHTMLScriptElement.cpp
--- a/content/base/public/nsIScriptElement.h
+++ b/content/base/public/nsIScriptElement.h
@@ -41,16 +41,17 @@
 
 #include "nsISupports.h"
 #include "nsIURI.h"
 #include "nsCOMPtr.h"
 #include "nsIScriptLoaderObserver.h"
 #include "nsWeakPtr.h"
 #include "nsIParser.h"
 #include "nsContentCreatorFunctions.h"
+#include "nsIDOMHTMLScriptElement.h"
 
 #define NS_ISCRIPTELEMENT_IID \
 { 0x6d625b30, 0xfac4, 0x11de, \
 { 0x8a, 0x39, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 } }
 
 /**
  * Internal interface implemented by script elements
  */
@@ -58,16 +59,18 @@ class nsIScriptElement : public nsIScrip
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISCRIPTELEMENT_IID)
 
   nsIScriptElement(mozilla::dom::FromParser aFromParser)
     : mLineNumber(0),
       mAlreadyStarted(PR_FALSE),
       mMalformed(PR_FALSE),
       mDoneAddingChildren(PR_TRUE),
+      mForceAsync(aFromParser == mozilla::dom::NOT_FROM_PARSER ||
+                  aFromParser == mozilla::dom::FROM_PARSER_FRAGMENT),
       mFrozen(PR_FALSE),
       mDefer(PR_FALSE),
       mAsync(PR_FALSE),
       mParserCreated(aFromParser == mozilla::dom::FROM_PARSER_FRAGMENT ?
                      mozilla::dom::NOT_FROM_PARSER : aFromParser),
                      // Fragment parser-created scripts (if executable)
                      // behave like script-created scripts.
       mCreatorParser(nsnull)
@@ -154,16 +157,22 @@ public:
   }
 
   void LoseParserInsertedness()
   {
     mFrozen = PR_FALSE;
     mUri = nsnull;
     mCreatorParser = nsnull;
     mParserCreated = mozilla::dom::NOT_FROM_PARSER;
+    PRBool async = PR_FALSE;
+    nsCOMPtr<nsIDOMHTMLScriptElement> htmlScript = do_QueryInterface(this);
+    if (htmlScript) {
+      htmlScript->GetAsync(&async);
+    }
+    mForceAsync = !async;
   }
 
   void SetCreatorParser(nsIParser* aParser)
   {
     mCreatorParser = getter_AddRefs(NS_GetWeakReference(aParser));
   }
 
   /**
@@ -214,16 +223,22 @@ protected:
   PRPackedBool mMalformed;
   
   /**
    * False if parser-inserted but the parser hasn't triggered running yet.
    */
   PRPackedBool mDoneAddingChildren;
 
   /**
+   * If true, the .async property returns true instead of reflecting the
+   * content attribute.
+   */
+  PRPackedBool mForceAsync;
+
+  /**
    * Whether src, defer and async are frozen.
    */
   PRPackedBool mFrozen;
   
   /**
    * The effective deferredness.
    */
   PRPackedBool mDefer;
--- a/content/base/test/test_bug602838.html
+++ b/content/base/test/test_bug602838.html
@@ -11,33 +11,52 @@ https://bugzilla.mozilla.org/show_bug.cg
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=602838">Mozilla Bug 602838</a>
 <p id="display"></p>
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
+<script id=withasync async></script>
+<script id=withoutasync></script>
 <script class="testbody" type="text/javascript">
 
 /** Test for Bug 602838 **/
 SimpleTest.waitForExplicitFinish();
 var firstRan = false;
 var asyncRan = false;
 
+var withoutasync = document.getElementById("withoutasync");
+ok(withoutasync.async, "When a script loses parser-insertedness, it should become async.");
+
+var withasync = document.getElementById("withasync");
+ok(withasync.async, "A script with the async content attribute should have the DOM attribute reporting true.");
+withasync.removeAttribute("async");
+ok(!withasync.async, "Should be able to remove asyncness from a script that had the async content attribute when losing parser-insertedness by removing the content attribute.");
+
 var s = document.createElement("script");
+ok(s.async, "Script-created scripts should default to .async=true");
+ok(!s.hasAttribute("async"), "Script-created scripts should not have the async content attribute by default.");
+s.removeAttribute("async");
+ok(s.async, "Removing a non-existing content-attribute should not have an effect on the forced async DOM property.");
+s.setAttribute("async", "");
+ok(s.async, "The async DOM property should still be true.");
+s.removeAttribute("async");
+ok(!s.async, "When a previously present async content attribute is removed, the DOM property should become false.");
 s.src = "script_bug602838.sjs";
 document.body.appendChild(s);
 
 s = document.createElement("script");
 s.src = "data:text/javascript,ok(firstRan, 'The first script should have run'); SimpleTest.finish();";
+s.async = false;
+ok(!s.async, "Setting the async DOM property to false should turned of forcing async to true.");
 document.body.appendChild(s);
 
 s = document.createElement("script");
 s.src = "data:text/javascript,ok(!firstRan, 'Non-async should not have run yet.'); asyncRan = true;";
-s.async = true;
 document.body.appendChild(s);
 
 </script>
 </pre>
 </body>
 </html>
 
--- a/content/html/content/src/nsHTMLScriptElement.cpp
+++ b/content/html/content/src/nsHTMLScriptElement.cpp
@@ -340,16 +340,20 @@ public:
 
   virtual nsresult GetInnerHTML(nsAString& aInnerHTML);
   virtual nsresult SetInnerHTML(const nsAString& aInnerHTML);
   virtual nsresult DoneAddingChildren(PRBool aHaveNotified);
   virtual PRBool IsDoneAddingChildren();
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
+  // nsGenericElement
+  virtual nsresult AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
+                                const nsAString* aValue, PRBool aNotify);
+
   virtual nsXPCClassInfo* GetClassInfo();
 protected:
   PRBool IsOnloadEventForWindow();
 
 
   // Pointer to the script handler helper object (OWNING reference)
   nsCOMPtr<nsHTMLScriptEventHandler> mScriptEventHandler;
 
@@ -449,23 +453,50 @@ NS_IMETHODIMP
 nsHTMLScriptElement::SetText(const nsAString& aValue)
 {
   return nsContentUtils::SetNodeTextContent(this, aValue, PR_TRUE);
 }
 
 
 NS_IMPL_STRING_ATTR(nsHTMLScriptElement, Charset, charset)
 NS_IMPL_BOOL_ATTR(nsHTMLScriptElement, Defer, defer)
-NS_IMPL_BOOL_ATTR(nsHTMLScriptElement, Async, async)
 NS_IMPL_URI_ATTR(nsHTMLScriptElement, Src, src)
 NS_IMPL_STRING_ATTR(nsHTMLScriptElement, Type, type)
 NS_IMPL_STRING_ATTR(nsHTMLScriptElement, HtmlFor, _for)
 NS_IMPL_STRING_ATTR(nsHTMLScriptElement, Event, event)
 
 nsresult
+nsHTMLScriptElement::GetAsync(PRBool* aValue)
+{
+  if (mForceAsync) {
+    *aValue = PR_TRUE;
+    return NS_OK;
+  }
+  return GetBoolAttr(nsGkAtoms::async, aValue);
+}
+
+nsresult
+nsHTMLScriptElement::SetAsync(PRBool aValue)
+{
+  mForceAsync = PR_FALSE;
+  return SetBoolAttr(nsGkAtoms::async, aValue);
+}
+
+nsresult
+nsHTMLScriptElement::AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
+                                  const nsAString* aValue, PRBool aNotify)
+{
+  if (nsGkAtoms::async == aName && kNameSpaceID_None == aNamespaceID) {
+    mForceAsync = PR_FALSE;
+  }
+  return nsGenericHTMLElement::AfterSetAttr(aNamespaceID, aName, aValue,
+                                            aNotify);
+}
+
+nsresult
 nsHTMLScriptElement::GetInnerHTML(nsAString& aInnerHTML)
 {
   nsContentUtils::GetNodeTextContent(this, PR_FALSE, aInnerHTML);
   return NS_OK;
 }
 
 nsresult
 nsHTMLScriptElement::SetInnerHTML(const nsAString& aInnerHTML)