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
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)