Chromium Code Reviews| Index: Source/core/dom/ScriptLoader.cpp |
| diff --git a/Source/core/dom/ScriptLoader.cpp b/Source/core/dom/ScriptLoader.cpp |
| index 6585f8d7680a82e49a5bc6bc81ef217d9b6a41b1..07a18092e922017b7c8386f736ccf790206146f9 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,7 +163,7 @@ 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) |
| +bool ScriptLoader::prepareScript(ResourcePtr<ScriptResource>* fetchedResource, const TextPosition& scriptStartPosition, LegacyTypeSupport supportLegacyTypes) |
| { |
| if (m_alreadyStarted) |
| return false; |
| @@ -215,9 +213,13 @@ bool ScriptLoader::prepareScript(const TextPosition& scriptStartPosition, Legacy |
| else |
| m_characterEncoding = elementDocument.charset(); |
| + ResourcePtr<ScriptResource> resource; |
| if (client->hasSourceAttribute()) { |
| - if (!fetchScript(client->sourceAttributeValue())) |
| + resource = fetchScript(client->sourceAttributeValue()); |
| + if (!resource) { |
| + dispatchErrorEvent(); |
| return false; |
| + } |
| } |
| if (client->hasSourceAttribute() && client->deferAttributeValue() && m_parserInserted && !client->asyncAttributeValue()) { |
| @@ -230,11 +232,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 +242,27 @@ bool ScriptLoader::prepareScript(const TextPosition& scriptStartPosition, Legacy |
| executeScript(ScriptSourceCode(scriptContent(), scriptURL, position)); |
| } |
| + if (resource) { |
| + // 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(). |
| + if (fetchedResource) |
| + *fetchedResource = resource; |
| + setResource(resource); |
| + } |
| + |
| return true; |
| } |
| -bool ScriptLoader::fetchScript(const String& sourceUrl) |
| +ResourcePtr<ScriptResource> ScriptLoader::fetchScript(const String& sourceUrl) |
| { |
| ASSERT(m_element); |
| RefPtr<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 +275,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 +314,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 +346,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 +356,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 +372,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 +385,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; |
| } |
| } |
| + |
|
Nate Chapin
2014/05/07 18:13:10
Nit: Remove this line.
|
| bool ScriptLoader::ignoresLoadRequest() const |
| { |
| return m_alreadyStarted || m_isExternalScript || m_parserInserted || !element() || !element()->inDocument(); |