| Index: third_party/WebKit/Source/core/dom/PendingScript.cpp
|
| diff --git a/third_party/WebKit/Source/core/dom/PendingScript.cpp b/third_party/WebKit/Source/core/dom/PendingScript.cpp
|
| index 7ea074252620e6ed402a035c3bbe8bfceba0d48e..36891d53430be82b931e1f33a7faf12fa213a820 100644
|
| --- a/third_party/WebKit/Source/core/dom/PendingScript.cpp
|
| +++ b/third_party/WebKit/Source/core/dom/PendingScript.cpp
|
| @@ -25,10 +25,15 @@
|
|
|
| #include "core/dom/PendingScript.h"
|
|
|
| +#include "bindings/core/v8/ScriptController.h"
|
| #include "bindings/core/v8/ScriptSourceCode.h"
|
| #include "core/dom/Element.h"
|
| +#include "core/dom/ScriptLoader.h"
|
| +#include "core/dom/TaskRunnerHelper.h"
|
| +#include "core/frame/LocalFrame.h"
|
| #include "core/frame/SubresourceIntegrity.h"
|
| #include "platform/SharedBuffer.h"
|
| +#include "platform/instrumentation/tracing/TraceEvent.h"
|
| #include "wtf/CurrentTime.h"
|
|
|
| namespace blink {
|
| @@ -52,6 +57,7 @@ PendingScript::PendingScript(Element* element,
|
| const TextPosition& startingPosition,
|
| bool isForTesting)
|
| : m_watchingForLoad(false),
|
| + m_readyState(resource ? kWaitingForResource : kReady),
|
| m_element(element),
|
| m_startingPosition(startingPosition),
|
| m_integrityFailure(false),
|
| @@ -99,7 +105,7 @@ void PendingScript::watchForLoad(PendingScriptClient* client) {
|
| m_watchingForLoad = true;
|
| m_client = client;
|
| if (isReady())
|
| - m_client->pendingScriptFinished(this);
|
| + client->pendingScriptFinished(this);
|
| }
|
|
|
| void PendingScript::stopWatchingForLoad() {
|
| @@ -121,6 +127,51 @@ Element* PendingScript::element() const {
|
| void PendingScript::streamingFinished() {
|
| checkState();
|
| DCHECK(resource());
|
| + fetchFinished();
|
| +}
|
| +
|
| +void PendingScript::fetchFinished() {
|
| + advanceReadyState(kWaitingForCompile);
|
| +
|
| + TRACE_EVENT_WITH_FLOW0("blink", "PendingScript compile", this,
|
| + TRACE_EVENT_FLAG_FLOW_OUT);
|
| + LocalFrame* frame = m_element ? m_element->document().frame() : nullptr;
|
| + if (!frame) {
|
| + // TODO(jbroman): A way of telling the client that it failed, without making
|
| + // the client try again, would be great.
|
| + compileFinished();
|
| + return;
|
| + }
|
| +
|
| + ScriptState::Scope scope(ScriptState::forMainWorld(frame));
|
| + bool errorOccurred;
|
| + ScriptSourceCode sourceCode = getSource(KURL(), errorOccurred);
|
| +
|
| + if (errorOccurred) {
|
| + // TODO(jbroman): A way of telling the client that it failed, without making
|
| + // the client try again, would be great.
|
| + compileFinished();
|
| + return;
|
| + }
|
| +
|
| + const bool isExternalScript = true;
|
| + AccessControlStatus accessControlStatus =
|
| + ScriptLoader::accessControlStatusForScript(
|
| + isExternalScript, resource(),
|
| + m_element->document().getSecurityOrigin());
|
| + m_compiledScript =
|
| + frame->script().compileScriptInMainWorld(sourceCode, accessControlStatus);
|
| + // TODO(jbroman): Can this fail? Yes, it can.
|
| + // CHECK(m_compiledScript) << "no compiled script? :'(";
|
| + TaskRunnerHelper::get(TaskType::Networking, frame)
|
| + ->postTask(FROM_HERE, WTF::bind(&PendingScript::compileFinished,
|
| + wrapPersistent(this)));
|
| +}
|
| +
|
| +void PendingScript::compileFinished() {
|
| + TRACE_EVENT_WITH_FLOW0("blink", "PendingScript compile", this,
|
| + TRACE_EVENT_FLAG_FLOW_IN);
|
| + advanceReadyState(kReady);
|
| if (m_client)
|
| m_client->pendingScriptFinished(this);
|
| }
|
| @@ -202,10 +253,12 @@ void PendingScript::notifyFinished(Resource* resource) {
|
|
|
| // If script streaming is in use, the client will be notified in
|
| // streamingFinished.
|
| - if (m_streamer)
|
| + if (m_streamer) {
|
| + advanceReadyState(kWaitingForStreaming);
|
| m_streamer->notifyFinished(resource);
|
| - else if (m_client)
|
| - m_client->pendingScriptFinished(this);
|
| + } else {
|
| + fetchFinished();
|
| + }
|
| }
|
|
|
| void PendingScript::notifyAppendData(ScriptResource* resource) {
|
| @@ -217,6 +270,7 @@ DEFINE_TRACE(PendingScript) {
|
| visitor->trace(m_element);
|
| visitor->trace(m_streamer);
|
| visitor->trace(m_client);
|
| + visitor->trace(m_compiledScript);
|
| ResourceOwner<ScriptResource>::trace(visitor);
|
| MemoryCoordinatorClient::trace(visitor);
|
| }
|
| @@ -228,8 +282,12 @@ ScriptSourceCode PendingScript::getSource(const KURL& documentURL,
|
| errorOccurred = this->errorOccurred();
|
| if (resource()) {
|
| DCHECK(resource()->isLoaded());
|
| - if (m_streamer && !m_streamer->streamingSuppressed())
|
| + // Avoid consuming the streamed source code more than once.
|
| + // TODO(jbroman): Update this if we don't always do the precompile step.
|
| + if (m_streamer && !m_streamer->streamingSuppressed() &&
|
| + m_readyState < ReadyState::kReady) {
|
| return ScriptSourceCode(m_streamer, resource());
|
| + }
|
| return ScriptSourceCode(resource());
|
| }
|
|
|
| @@ -240,17 +298,15 @@ ScriptSourceCode PendingScript::getSource(const KURL& documentURL,
|
| void PendingScript::setStreamer(ScriptStreamer* streamer) {
|
| DCHECK(!m_streamer);
|
| DCHECK(!m_watchingForLoad);
|
| + DCHECK(!streamer->isFinished());
|
| + DCHECK_LT(m_readyState, kWaitingForStreaming);
|
| m_streamer = streamer;
|
| checkState();
|
| }
|
|
|
| bool PendingScript::isReady() const {
|
| checkState();
|
| - if (resource()) {
|
| - return resource()->isLoaded() && (!m_streamer || m_streamer->isFinished());
|
| - }
|
| -
|
| - return true;
|
| + return m_readyState == kReady;
|
| }
|
|
|
| bool PendingScript::errorOccurred() const {
|
|
|