Index: Source/core/dom/ScriptLoader.cpp |
diff --git a/Source/core/dom/ScriptLoader.cpp b/Source/core/dom/ScriptLoader.cpp |
index 0b3ab8bf8fcc993c01c8f51619e28583f17470cb..6c8c4a3a72a7f99c8be1df7e48f200647f6d8df1 100644 |
--- a/Source/core/dom/ScriptLoader.cpp |
+++ b/Source/core/dom/ScriptLoader.cpp |
@@ -54,7 +54,6 @@ namespace WebCore { |
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) |
@@ -73,7 +72,6 @@ ScriptLoader::ScriptLoader(Element* element, bool parserInserted, bool alreadySt |
ScriptLoader::~ScriptLoader() |
{ |
- stopLoadRequest(); |
} |
void ScriptLoader::didNotifySubtreeInsertionsToDocument() |
@@ -165,10 +163,10 @@ bool ScriptLoader::isScriptTypeSupported(LegacyTypeSupport supportLegacyTypes) c |
} |
// http://dev.w3.org/html5/spec/Overview.html#prepare-a-script |
-bool ScriptLoader::prepareScript(const TextPosition& scriptStartPosition, LegacyTypeSupport supportLegacyTypes) |
+ScriptPrep ScriptLoader::prepareScript(const TextPosition& scriptStartPosition, LegacyTypeSupport supportLegacyTypes) |
{ |
if (m_alreadyStarted) |
- return false; |
+ return ScriptPrep::failed(); |
ScriptLoaderClient* client = this->client(); |
@@ -185,13 +183,13 @@ bool ScriptLoader::prepareScript(const TextPosition& scriptStartPosition, Legacy |
// FIXME: HTML5 spec says we should check that all children are either comments or empty text nodes. |
if (!client->hasSourceAttribute() && !m_element->firstChild()) |
- return false; |
+ return ScriptPrep::failed(); |
if (!m_element->inDocument()) |
- return false; |
+ return ScriptPrep::failed(); |
if (!isScriptTypeSupported(supportLegacyTypes)) |
- return false; |
+ return ScriptPrep::failed(); |
if (wasParserInserted) { |
m_parserInserted = true; |
@@ -205,19 +203,24 @@ bool ScriptLoader::prepareScript(const TextPosition& scriptStartPosition, Legacy |
Document* contextDocument = elementDocument.contextDocument().get(); |
if (!contextDocument || !contextDocument->allowExecutingScripts(m_element)) |
- return false; |
+ return ScriptPrep::failed(); |
if (!isScriptForEventSupported()) |
- return false; |
+ return ScriptPrep::failed(); |
if (!client->charsetAttributeValue().isEmpty()) |
m_characterEncoding = client->charsetAttributeValue(); |
else |
m_characterEncoding = elementDocument.charset(); |
+ ResourcePtr<ScriptResource> resource; |
if (client->hasSourceAttribute()) { |
- if (!fetchScript(client->sourceAttributeValue())) |
- return false; |
+ resource = fetchScript(client->sourceAttributeValue()); |
+ if (!resource) { |
+ dispatchErrorEvent(); |
+ return ScriptPrep::failed(); |
+ } |
+ |
} |
if (client->hasSourceAttribute() && client->deferAttributeValue() && m_parserInserted && !client->asyncAttributeValue()) { |
@@ -230,11 +233,9 @@ bool ScriptLoader::prepareScript(const TextPosition& scriptStartPosition, Legacy |
m_readyToBeParserExecuted = true; |
} else if (client->hasSourceAttribute() && !client->asyncAttributeValue() && !m_forceAsync) { |
m_willExecuteInOrder = true; |
- contextDocument->scriptRunner()->queueScriptForExecution(this, m_resource, ScriptRunner::IN_ORDER_EXECUTION); |
- m_resource->addClient(this); |
+ contextDocument->scriptRunner()->queueScriptForExecution(this, resource, ScriptRunner::IN_ORDER_EXECUTION); |
} else if (client->hasSourceAttribute()) { |
- contextDocument->scriptRunner()->queueScriptForExecution(this, m_resource, ScriptRunner::ASYNC_EXECUTION); |
- m_resource->addClient(this); |
+ contextDocument->scriptRunner()->queueScriptForExecution(this, resource, ScriptRunner::ASYNC_EXECUTION); |
} else { |
// Reset line numbering for nested writes. |
TextPosition position = elementDocument.isInDocumentWrite() ? TextPosition() : scriptStartPosition; |
@@ -242,18 +243,25 @@ bool ScriptLoader::prepareScript(const TextPosition& scriptStartPosition, Legacy |
executeScript(ScriptSourceCode(scriptContent(), scriptURL, position)); |
} |
- return true; |
+ // 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); |
} |
-bool ScriptLoader::fetchScript(const String& sourceUrl) |
+ResourcePtr<ScriptResource> ScriptLoader::fetchScript(const String& sourceUrl) |
{ |
ASSERT(m_element); |
RefPtrWillBeRawPtr<Document> elementDocument(m_element->document()); |
if (!m_element->inDocument() || m_element->document() != elementDocument) |
- return false; |
+ return ResourcePtr<ScriptResource>(); |
- ASSERT(!m_resource); |
+ ASSERT(!resource()); |
+ ResourcePtr<ScriptResource> resource; |
if (!stripLeadingAndTrailingHTMLSpaces(sourceUrl).isEmpty()) { |
FetchRequest request(ResourceRequest(elementDocument->completeURL(sourceUrl)), m_element->localName()); |
@@ -266,15 +274,11 @@ bool ScriptLoader::fetchScript(const String& sourceUrl) |
if (isValidScriptNonce) |
request.setContentSecurityCheck(DoNotCheckContentSecurityPolicy); |
- m_resource = elementDocument->fetcher()->fetchScript(request); |
+ resource = elementDocument->fetcher()->fetchScript(request); |
m_isExternalScript = true; |
} |
- if (m_resource) |
- return true; |
- |
- dispatchErrorEvent(); |
- return false; |
+ return resource; |
} |
bool isHTMLScriptLoader(Element* element) |
@@ -309,7 +313,7 @@ void ScriptLoader::executeScript(const ScriptSourceCode& sourceCode) |
return; |
if (m_isExternalScript) { |
- ScriptResource* resource = m_resource ? m_resource.get() : sourceCode.resource(); |
+ ScriptResource* resource = this->resource() ? this->resource() : 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; |
@@ -341,15 +345,6 @@ void ScriptLoader::executeScript(const ScriptSourceCode& sourceCode) |
} |
} |
-void ScriptLoader::stopLoadRequest() |
-{ |
- if (m_resource) { |
- if (!m_willBeParserExecuted) |
- m_resource->removeClient(this); |
- m_resource = 0; |
- } |
-} |
- |
void ScriptLoader::execute(ScriptResource* resource) |
{ |
ASSERT(!m_willBeParserExecuted); |
@@ -360,12 +355,13 @@ void ScriptLoader::execute(ScriptResource* resource) |
executeScript(ScriptSourceCode(resource)); |
dispatchLoadEvent(); |
} |
- resource->removeClient(this); |
+ |
+ clearResource(); |
} |
void ScriptLoader::cancel(Document* contextDocument) |
{ |
- if (!m_resource) |
+ if (!resource()) |
return; |
finishLoading(contextDocument, FinishWithCancel); |
} |
@@ -375,11 +371,12 @@ void ScriptLoader::notifyFinished(Resource* resource) |
// 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 m_resource to check if this function is already called. |
- ASSERT_UNUSED(resource, resource == m_resource); |
- if (!m_resource) |
+ // We use resource() to check if this function is already called. |
+ ASSERT_UNUSED(resource, resource == this->resource()); |
+ if (!this->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); |
@@ -387,29 +384,28 @@ void ScriptLoader::notifyFinished(Resource* resource) |
void ScriptLoader::finishLoading(Document* contextDocument, ScriptLoader::FinishType type) |
{ |
- if (!contextDocument) |
- return; |
+ if (!m_willBeParserExecuted && contextDocument) |
+ notifyRunnerFinishLoading(contextDocument->scriptRunner(), type); |
+ clearResource(); |
+} |
+void ScriptLoader::notifyRunnerFinishLoading(ScriptRunner* runner, ScriptLoader::FinishType type) |
+{ |
switch (type) { |
case FinishWithCancel: |
- if (!m_willBeParserExecuted) |
- contextDocument->scriptRunner()->notifyScriptLoadError(this, m_willExecuteInOrder ? ScriptRunner::IN_ORDER_EXECUTION : ScriptRunner::ASYNC_EXECUTION); |
- stopLoadRequest(); |
+ runner->notifyScriptLoadError(this, m_willExecuteInOrder ? ScriptRunner::IN_ORDER_EXECUTION : ScriptRunner::ASYNC_EXECUTION); |
break; |
case FinishWithError: |
- ASSERT(!m_willBeParserExecuted); |
dispatchErrorEvent(); |
- contextDocument->scriptRunner()->notifyScriptLoadError(this, m_willExecuteInOrder ? ScriptRunner::IN_ORDER_EXECUTION : ScriptRunner::ASYNC_EXECUTION); |
- m_resource = 0; |
+ runner->notifyScriptLoadError(this, m_willExecuteInOrder ? ScriptRunner::IN_ORDER_EXECUTION : ScriptRunner::ASYNC_EXECUTION); |
break; |
case FinishSuccessfully: |
- ASSERT(!m_willBeParserExecuted); |
- contextDocument->scriptRunner()->notifyScriptReady(this, m_willExecuteInOrder ? ScriptRunner::IN_ORDER_EXECUTION : ScriptRunner::ASYNC_EXECUTION); |
- m_resource = 0; |
+ runner->notifyScriptReady(this, m_willExecuteInOrder ? ScriptRunner::IN_ORDER_EXECUTION : ScriptRunner::ASYNC_EXECUTION); |
break; |
} |
} |
+ |
bool ScriptLoader::ignoresLoadRequest() const |
{ |
return m_alreadyStarted || m_isExternalScript || m_parserInserted || !element() || !element()->inDocument(); |