Index: trunk/Source/core/dom/ScriptLoader.cpp |
=================================================================== |
--- trunk/Source/core/dom/ScriptLoader.cpp (revision 174070) |
+++ trunk/Source/core/dom/ScriptLoader.cpp (working copy) |
@@ -54,6 +54,7 @@ |
ScriptLoader::ScriptLoader(Element* element, bool parserInserted, bool alreadyStarted) |
: m_element(element) |
+ , m_resource(0) |
, m_startLineNumber(WTF::OrdinalNumber::beforeFirst()) |
, m_parserInserted(parserInserted) |
, m_isExternalScript(false) |
@@ -72,6 +73,7 @@ |
ScriptLoader::~ScriptLoader() |
{ |
+ stopLoadRequest(); |
} |
void ScriptLoader::didNotifySubtreeInsertionsToDocument() |
@@ -163,10 +165,10 @@ |
} |
// http://dev.w3.org/html5/spec/Overview.html#prepare-a-script |
-ScriptPrep ScriptLoader::prepareScript(const TextPosition& scriptStartPosition, LegacyTypeSupport supportLegacyTypes) |
+bool ScriptLoader::prepareScript(const TextPosition& scriptStartPosition, LegacyTypeSupport supportLegacyTypes) |
{ |
if (m_alreadyStarted) |
- return ScriptPrep::failed(); |
+ return false; |
ScriptLoaderClient* client = this->client(); |
@@ -183,13 +185,13 @@ |
// FIXME: HTML5 spec says we should check that all children are either comments or empty text nodes. |
if (!client->hasSourceAttribute() && !m_element->firstChild()) |
- return ScriptPrep::failed(); |
+ return false; |
if (!m_element->inDocument()) |
- return ScriptPrep::failed(); |
+ return false; |
if (!isScriptTypeSupported(supportLegacyTypes)) |
- return ScriptPrep::failed(); |
+ return false; |
if (wasParserInserted) { |
m_parserInserted = true; |
@@ -203,24 +205,19 @@ |
Document* contextDocument = elementDocument.contextDocument().get(); |
if (!contextDocument || !contextDocument->allowExecutingScripts(m_element)) |
- return ScriptPrep::failed(); |
+ return false; |
if (!isScriptForEventSupported()) |
- return ScriptPrep::failed(); |
+ return false; |
if (!client->charsetAttributeValue().isEmpty()) |
m_characterEncoding = client->charsetAttributeValue(); |
else |
m_characterEncoding = elementDocument.charset(); |
- ResourcePtr<ScriptResource> resource; |
if (client->hasSourceAttribute()) { |
- resource = fetchScript(client->sourceAttributeValue()); |
- if (!resource) { |
- dispatchErrorEvent(); |
- return ScriptPrep::failed(); |
- } |
- |
+ if (!fetchScript(client->sourceAttributeValue())) |
+ return false; |
} |
if (client->hasSourceAttribute() && client->deferAttributeValue() && m_parserInserted && !client->asyncAttributeValue()) { |
@@ -233,9 +230,11 @@ |
m_readyToBeParserExecuted = true; |
} else if (client->hasSourceAttribute() && !client->asyncAttributeValue() && !m_forceAsync) { |
m_willExecuteInOrder = true; |
- contextDocument->scriptRunner()->queueScriptForExecution(this, resource, ScriptRunner::IN_ORDER_EXECUTION); |
+ contextDocument->scriptRunner()->queueScriptForExecution(this, m_resource, ScriptRunner::IN_ORDER_EXECUTION); |
+ m_resource->addClient(this); |
} else if (client->hasSourceAttribute()) { |
- contextDocument->scriptRunner()->queueScriptForExecution(this, resource, ScriptRunner::ASYNC_EXECUTION); |
+ contextDocument->scriptRunner()->queueScriptForExecution(this, m_resource, ScriptRunner::ASYNC_EXECUTION); |
+ m_resource->addClient(this); |
} else { |
// Reset line numbering for nested writes. |
TextPosition position = elementDocument.isInDocumentWrite() ? TextPosition() : scriptStartPosition; |
@@ -243,25 +242,18 @@ |
executeScript(ScriptSourceCode(scriptContent(), scriptURL, position)); |
} |
- // FIXME: This second "subscribing" parameter is a mess. We shouldn't have to need this. |
- if (resource) |
- setResource(resource, !m_willBeParserExecuted); |
- |
- // We have to return fetchedResource instead of let callers ask ScriptLoader::resource() |
- // because resource() can be null when it is accessed: Following setResource() can trigger clearResource(). |
- return ScriptPrep(true, resource); |
+ return true; |
} |
-ResourcePtr<ScriptResource> ScriptLoader::fetchScript(const String& sourceUrl) |
+bool ScriptLoader::fetchScript(const String& sourceUrl) |
{ |
ASSERT(m_element); |
RefPtrWillBeRawPtr<Document> elementDocument(m_element->document()); |
if (!m_element->inDocument() || m_element->document() != elementDocument) |
- return ResourcePtr<ScriptResource>(); |
+ return false; |
- ASSERT(!resource()); |
- ResourcePtr<ScriptResource> resource; |
+ ASSERT(!m_resource); |
if (!stripLeadingAndTrailingHTMLSpaces(sourceUrl).isEmpty()) { |
FetchRequest request(ResourceRequest(elementDocument->completeURL(sourceUrl)), m_element->localName()); |
@@ -274,11 +266,15 @@ |
if (isValidScriptNonce) |
request.setContentSecurityCheck(DoNotCheckContentSecurityPolicy); |
- resource = elementDocument->fetcher()->fetchScript(request); |
+ m_resource = elementDocument->fetcher()->fetchScript(request); |
m_isExternalScript = true; |
} |
- return resource; |
+ if (m_resource) |
+ return true; |
+ |
+ dispatchErrorEvent(); |
+ return false; |
} |
bool isHTMLScriptLoader(Element* element) |
@@ -313,7 +309,7 @@ |
return; |
if (m_isExternalScript) { |
- ScriptResource* resource = this->resource() ? this->resource() : sourceCode.resource(); |
+ ScriptResource* resource = m_resource ? m_resource.get() : sourceCode.resource(); |
if (resource && !resource->mimeTypeAllowedByNosniff()) { |
contextDocument->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "Refused to execute script from '" + resource->url().elidedString() + "' because its MIME type ('" + resource->mimeType() + "') is not executable, and strict MIME type checking is enabled."); |
return; |
@@ -345,6 +341,15 @@ |
} |
} |
+void ScriptLoader::stopLoadRequest() |
+{ |
+ if (m_resource) { |
+ if (!m_willBeParserExecuted) |
+ m_resource->removeClient(this); |
+ m_resource = 0; |
+ } |
+} |
+ |
void ScriptLoader::execute(ScriptResource* resource) |
{ |
ASSERT(!m_willBeParserExecuted); |
@@ -355,13 +360,12 @@ |
executeScript(ScriptSourceCode(resource)); |
dispatchLoadEvent(); |
} |
- |
- clearResource(); |
+ resource->removeClient(this); |
} |
void ScriptLoader::cancel(Document* contextDocument) |
{ |
- if (!resource()) |
+ if (!m_resource) |
return; |
finishLoading(contextDocument, FinishWithCancel); |
} |
@@ -371,12 +375,11 @@ |
// Resource possibly invokes this notifyFinished() more than |
// once because ScriptLoader doesn't unsubscribe itself from |
// Resource here and does it in execute() instead. |
- // We use resource() to check if this function is already called. |
- ASSERT_UNUSED(resource, resource == this->resource()); |
- if (!this->resource()) |
+ // We use m_resource to check if this function is already called. |
+ ASSERT_UNUSED(resource, resource == m_resource); |
+ if (!m_resource) |
return; |
- RefPtr<Element> protect(m_element); |
RefPtr<Document> elementDocument(m_element->document()); |
RefPtr<Document> contextDocument = elementDocument->contextDocument().get(); |
finishLoading(contextDocument.get(), resource->errorOccurred() ? FinishWithError : FinishSuccessfully); |
@@ -384,28 +387,29 @@ |
void ScriptLoader::finishLoading(Document* contextDocument, ScriptLoader::FinishType type) |
{ |
- if (!m_willBeParserExecuted && contextDocument) |
- notifyRunnerFinishLoading(contextDocument->scriptRunner(), type); |
- clearResource(); |
-} |
+ if (!contextDocument) |
+ return; |
-void ScriptLoader::notifyRunnerFinishLoading(ScriptRunner* runner, ScriptLoader::FinishType type) |
-{ |
switch (type) { |
case FinishWithCancel: |
- runner->notifyScriptLoadError(this, m_willExecuteInOrder ? ScriptRunner::IN_ORDER_EXECUTION : ScriptRunner::ASYNC_EXECUTION); |
+ if (!m_willBeParserExecuted) |
+ contextDocument->scriptRunner()->notifyScriptLoadError(this, m_willExecuteInOrder ? ScriptRunner::IN_ORDER_EXECUTION : ScriptRunner::ASYNC_EXECUTION); |
+ stopLoadRequest(); |
break; |
case FinishWithError: |
+ ASSERT(!m_willBeParserExecuted); |
dispatchErrorEvent(); |
- runner->notifyScriptLoadError(this, m_willExecuteInOrder ? ScriptRunner::IN_ORDER_EXECUTION : ScriptRunner::ASYNC_EXECUTION); |
+ contextDocument->scriptRunner()->notifyScriptLoadError(this, m_willExecuteInOrder ? ScriptRunner::IN_ORDER_EXECUTION : ScriptRunner::ASYNC_EXECUTION); |
+ m_resource = 0; |
break; |
case FinishSuccessfully: |
- runner->notifyScriptReady(this, m_willExecuteInOrder ? ScriptRunner::IN_ORDER_EXECUTION : ScriptRunner::ASYNC_EXECUTION); |
+ ASSERT(!m_willBeParserExecuted); |
+ contextDocument->scriptRunner()->notifyScriptReady(this, m_willExecuteInOrder ? ScriptRunner::IN_ORDER_EXECUTION : ScriptRunner::ASYNC_EXECUTION); |
+ m_resource = 0; |
break; |
} |
} |
- |
bool ScriptLoader::ignoresLoadRequest() const |
{ |
return m_alreadyStarted || m_isExternalScript || m_parserInserted || !element() || !element()->inDocument(); |