2011-03-15  James Simonsen  <simonjam@chromium.org>

        Reviewed by Tony Gentilcore.

        Need different behavior for ensuring execution order of dynamically loaded scripts
        https://bugs.webkit.org/show_bug.cgi?id=50115

        Dynamically added scripts with async=false will load in parallel, but execute in order.
        See: http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#force-async

        * fast/dom/HTMLScriptElement/script-async-attr-expected.txt: Added test cases for forceAsync.
        * fast/dom/HTMLScriptElement/script-async-attr.html: Ditto.
        * http/tests/misc/script-async-load-execute-in-order-expected.txt: Added.
        * http/tests/misc/script-async-load-execute-in-order.html: Added.
2011-03-15  James Simonsen  <simonjam@chromium.org>

        Reviewed by Tony Gentilcore.

        Need different behavior for ensuring execution order of dynamically loaded scripts
        https://bugs.webkit.org/show_bug.cgi?id=50115

        Dynamically added scripts with async=false will load in parallel, but execute in order.
        See: http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#force-async

        Tests: fast/dom/HTMLScriptElement/script-async-attr.html
               http/tests/misc/script-async-load-execute-in-order.html

        * Android.mk: Rename AsyncScriptRunner -> ScriptRunner.
        * CMakeLists.txt: Ditto.
        * GNUmakefile.am: Ditto.
        * WebCore.gypi: Ditto.
        * WebCore.pro: Ditto.
        * WebCore.vcproj/WebCore.vcproj: Ditto.
        * WebCore.xcodeproj/project.pbxproj: Ditto.
        * dom/DOMAllInOne.cpp: Ditto.
        * dom/Document.cpp:
        (WebCore::Document::Document): Ditto.
        (WebCore::Document::~Document): Ditto.
        * dom/Document.h:
        (WebCore::Document::scriptRunner): Ditto.
        * dom/ScriptElement.cpp:
        (WebCore::ScriptElement::ScriptElement): Added forceAsync and willExecuteInOrder.
        (WebCore::ScriptElement::handleAsyncAttribute): Called by HTMLScriptElement when async attribute changes.
        (WebCore::ScriptElement::prepareScript): Added support for forceAsync.
        (WebCore::ScriptElement::notifyFinished): Tell ScriptRunner to execute in order if needed.
        * dom/ScriptElement.h:
        (WebCore::ScriptElement::forceAsync): Added.
        * dom/ScriptRunner.cpp: Renamed from Source/WebCore/dom/AsyncScriptRunner.cpp.
        (WebCore::ScriptRunner::ScriptRunner): Added in-order script queue.
        (WebCore::ScriptRunner::~ScriptRunner): Ditto.
        (WebCore::ScriptRunner::executeScriptSoon):
        (WebCore::ScriptRunner::queueScriptForInOrderExecution): Added.
        (WebCore::ScriptRunner::suspend):
        (WebCore::ScriptRunner::resume):
        (WebCore::ScriptRunner::timerFired): Execute in-order scripts if ready.
        * dom/ScriptRunner.h: Renamed from Source/WebCore/dom/AsyncScriptRunner.h.
        (WebCore::ScriptRunner::create):
        (WebCore::ScriptRunner::hasPendingScripts): Check for in-order scripts too.
        * html/HTMLScriptElement.cpp:
        (WebCore::HTMLScriptElement::attributeChanged): Notify ScriptElement when async changes.
        (WebCore::HTMLScriptElement::setAsync): Ditto.
        (WebCore::HTMLScriptElement::async): Include forceAsync in calculation.
        * html/HTMLScriptElement.h:
        * html/HTMLScriptElement.idl: Removed Reflect from async for custom behavior.
        * page/PageGroupLoadDeferrer.cpp:
        (WebCore::PageGroupLoadDeferrer::PageGroupLoadDeferrer): Rename AsyncScriptRunner -> ScriptRunner.
        (WebCore::PageGroupLoadDeferrer::~PageGroupLoadDeferrer): Ditto.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@81198 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/dom/ScriptElement.cpp b/Source/WebCore/dom/ScriptElement.cpp
index 3bba9a0..b4d3670 100644
--- a/Source/WebCore/dom/ScriptElement.cpp
+++ b/Source/WebCore/dom/ScriptElement.cpp
@@ -24,7 +24,6 @@
 #include "config.h"
 #include "ScriptElement.h"
 
-#include "AsyncScriptRunner.h"
 #include "CachedScript.h"
 #include "CachedResourceLoader.h"
 #include "Document.h"
@@ -37,6 +36,7 @@
 #include "MIMETypeRegistry.h"
 #include "Page.h"
 #include "ScriptController.h"
+#include "ScriptRunner.h"
 #include "ScriptSourceCode.h"
 #include "ScriptValue.h"
 #include "Settings.h"
@@ -61,6 +61,8 @@
     , m_willBeParserExecuted(false)
     , m_readyToBeParserExecuted(false)
     , m_willExecuteWhenDocumentFinishedParsing(false)
+    , m_forceAsync(!parserInserted)
+    , m_willExecuteInOrder(false)
 {
     ASSERT(m_element);
 }
@@ -96,6 +98,11 @@
     prepareScript(); // FIXME: Provide a real starting line number here.
 }
 
+void ScriptElement::handleAsyncAttribute()
+{
+    m_forceAsync = false;
+}
+
 // Helper function
 static bool isLegacySupportedJavaScriptLanguage(const String& language)
 {
@@ -159,7 +166,8 @@
     } else
         wasParserInserted = false;
 
-    // FIXME: HTML5 spec says we should set forceAsync.
+    if (wasParserInserted && !asyncAttributeValue())
+        m_forceAsync = true;
 
     // FIXME: HTML5 spec says we should check that all children are either comments or empty text nodes.
     if (!hasSourceAttribute() && !m_element->firstChild())
@@ -171,8 +179,10 @@
     if (!isScriptTypeSupported(supportLegacyTypes))
         return false;
 
-    if (wasParserInserted)
+    if (wasParserInserted) {
         m_parserInserted = true;
+        m_forceAsync = false;
+    }
 
     m_alreadyStarted = true;
 
@@ -207,6 +217,10 @@
     else if (!hasSourceAttribute() && m_parserInserted && !m_element->document()->haveStylesheetsLoaded()) {
         m_willBeParserExecuted = true;
         m_readyToBeParserExecuted = true;
+    } else if (hasSourceAttribute() && !asyncAttributeValue() && !m_forceAsync) {
+        m_willExecuteInOrder = true;
+        m_element->document()->scriptRunner()->queueScriptForExecution(this, m_cachedScript, ScriptRunner::IN_ORDER_EXECUTION);
+        m_cachedScript->addClient(this);
     } else if (hasSourceAttribute())
         m_cachedScript->addClient(this);
     else
@@ -286,7 +300,10 @@
 {
     ASSERT(!m_willBeParserExecuted);
     ASSERT_UNUSED(o, o == m_cachedScript);
-    m_element->document()->asyncScriptRunner()->executeScriptSoon(this, m_cachedScript);
+    if (m_willExecuteInOrder)
+        m_element->document()->scriptRunner()->notifyInOrderScriptReady();
+    else
+        m_element->document()->scriptRunner()->queueScriptForExecution(this, m_cachedScript, ScriptRunner::ASYNC_EXECUTION);
     m_cachedScript = 0;
 }