Chromium Code Reviews| Index: third_party/WebKit/Source/core/workers/MainThreadWorklet.cpp |
| diff --git a/third_party/WebKit/Source/core/workers/MainThreadWorklet.cpp b/third_party/WebKit/Source/core/workers/MainThreadWorklet.cpp |
| index 1c7e06f83015b15769eed29befdbf54df2911f3f..59ecef3c7ed778f90922d2b98fe8ac2386fdb6c0 100644 |
| --- a/third_party/WebKit/Source/core/workers/MainThreadWorklet.cpp |
| +++ b/third_party/WebKit/Source/core/workers/MainThreadWorklet.cpp |
| @@ -26,10 +26,27 @@ int32_t GetNextRequestId() { |
| } // namespace |
| +// Implementation of the "pending tasks struct": |
| +// https://drafts.css-houdini.org/worklets/#pending-tasks-struct |
| +struct MainThreadWorklet::PendingTasks : public GarbageCollected<PendingTasks> { |
|
kouhei (in TOK)
2017/04/25 11:55:17
please make this a proper class
|
| + PendingTasks(int counter, ScriptPromiseResolver* resolver) |
| + : counter(counter), resolver(resolver) {} |
| + ~PendingTasks() = default; |
| + |
| + // The number of pending tasks. |
| + int counter; |
| + |
| + Member<ScriptPromiseResolver> resolver; |
| + |
| + DEFINE_INLINE_VIRTUAL_TRACE() { visitor->Trace(resolver); } |
| +}; |
| + |
| MainThreadWorklet::MainThreadWorklet(LocalFrame* frame) : Worklet(frame) { |
| - DCHECK(resolver_map_.IsEmpty()); |
| + DCHECK(pending_tasks_map_.IsEmpty()); |
|
kouhei (in TOK)
2017/04/25 11:55:18
I think we can safely omit this DCHECK.
|
| } |
| +// Implementation of the "addModule" algorithm: |
| +// https://drafts.css-houdini.org/worklets/#dom-worklet-addmodule |
| ScriptPromise MainThreadWorklet::addModule(ScriptState* script_state, |
| const String& url) { |
| DCHECK(IsMainThread()); |
|
kouhei (in TOK)
2017/04/25 11:55:17
Optional: I'd prefer to have all the steps in the
|
| @@ -39,6 +56,8 @@ ScriptPromise MainThreadWorklet::addModule(ScriptState* script_state, |
| "This frame is already detached")); |
| } |
| + // Step 4: "If moduleURLRecord is failure, then reject promise with a |
|
kouhei (in TOK)
2017/04/25 11:55:18
Can we rename the script_url var to module_url_rec
|
| + // "SyntaxError" DOMException and return promise." |
| KURL script_url = GetExecutionContext()->CompleteURL(url); |
|
kouhei (in TOK)
2017/04/25 11:55:17
Looks like CompleteURL part is the Step 3?
|
| if (!script_url.IsValid()) { |
| return ScriptPromise::RejectWithDOMException( |
| @@ -46,39 +65,81 @@ ScriptPromise MainThreadWorklet::addModule(ScriptState* script_state, |
| kSyntaxError, "'" + url + "' is not a valid URL.")); |
| } |
| - if (!IsInitialized()) |
| - Initialize(); |
| + // Step 10: "If the worklet's WorkletGlobalScopes is empty, run the following |
| + // steps:" |
| + // 10.1: "Create a WorkletGlobalScope given workletGlobalScopeType, |
| + // moduleResponsesMap, and outsideSettings." |
|
kouhei (in TOK)
2017/04/25 11:55:18
Add TODO(nhiroki) comment about the workletGlobalS
|
| + // 10.2: "Add the WorkletGlobalScope to worklet's WorkletGlobalScopes." |
| + if (global_scope_proxies_.IsEmpty()) |
| + CreateWorkletGlobalScope(); |
| + DCHECK(!global_scope_proxies_.IsEmpty()); |
| - int32_t request_id = GetNextRequestId(); |
| + // Step 11: "Let pendingTaskStruct be a new pending tasks struct with counter |
| + // initialized to the length of worklet' s WorkletGlobalScopes." |
| + const int32_t request_id = GetNextRequestId(); |
| ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); |
| + pending_tasks_map_.Set( |
| + request_id, new PendingTasks(global_scope_proxies_.size(), resolver)); |
| + |
| + // Step 12: "For each workletGlobalScope in the worklet's |
| + // WorkletGlobalScopes, queue a task on the workletGlobalScope to fetch and |
| + // invoke a worklet script given workletGlobalScope, moduleURLRecord, |
| + // moduleResponsesMap, credentialOptions, outsideSettings, pendingTaskStruct, |
| + // and promise." |
| ScriptPromise promise = resolver->Promise(); |
| - resolver_map_.Set(request_id, resolver); |
| - GetWorkletGlobalScopeProxy()->FetchAndInvokeScript(request_id, script_url); |
| + for (const auto& proxy : global_scope_proxies_) |
| + proxy->FetchAndInvokeScript(request_id, script_url); |
| + |
| return promise; |
| } |
| +// Worklet-side implementation of the "fetch and invoke a worklet script" |
| +// algorithm: |
| +// https://drafts.css-houdini.org/worklets/#fetch-and-invoke-a-worklet-script |
| void MainThreadWorklet::DidFetchAndInvokeScript(int32_t request_id, |
| bool success) { |
| DCHECK(IsMainThread()); |
| - ScriptPromiseResolver* resolver = resolver_map_.at(request_id); |
| - if (!resolver) |
| + PendingTasks* pending_tasks = pending_tasks_map_.at(request_id); |
|
kouhei (in TOK)
2017/04/25 11:55:18
Optional: map_.Find here to get iterator
|
| + if (!pending_tasks) |
| return; |
| - resolver_map_.erase(request_id); |
| + |
| + // Step 3: "If script is null, then queue a task on outsideSettings's |
| + // responsible event loop to run these steps:" |
|
kouhei (in TOK)
2017/04/25 11:55:18
Add TODO(nhiroki) or add note to justify not queui
|
| + // 3.1.2: "Reject promise with an "AbortError" DOMException." |
| if (!success) { |
| - resolver->Reject(DOMException::Create(kNetworkError)); |
| + pending_tasks_map_.erase(request_id); |
|
kouhei (in TOK)
2017/04/25 11:55:18
and trigger erase on the iterator?
|
| + // TODO(nhiroki): This should be kAbortError. |
| + pending_tasks->resolver->Reject(DOMException::Create(kNetworkError)); |
| return; |
| } |
| - resolver->Resolve(); |
| + |
| + // Step 5: "Queue a task on outsideSettings's responsible event loop to run |
| + // these steps:" |
|
kouhei (in TOK)
2017/04/25 11:55:17
Ditto.
|
| + // 5.1.1: "Decrement pendingTaskStruct's counter by 1." |
| + // 5.1.2: "If pendingTaskStruct's counter is 0, then resolve promise." |
| + DCHECK_GT(0, pending_tasks->counter); |
| + --pending_tasks->counter; |
| + if (pending_tasks->counter == 0) { |
| + pending_tasks_map_.erase(request_id); |
| + pending_tasks->resolver->Resolve(); |
| + } |
| +} |
| + |
| +void MainThreadWorklet::CreateWorkletGlobalScope() { |
| + if (!IsInitialized()) |
| + Initialize(); |
| } |
| void MainThreadWorklet::ContextDestroyed(ExecutionContext* execution_context) { |
| DCHECK(IsMainThread()); |
| - resolver_map_.clear(); |
| + pending_tasks_map_.clear(); |
| + for (const auto& proxy : global_scope_proxies_) |
| + proxy->TerminateWorkletGlobalScope(); |
| Worklet::ContextDestroyed(execution_context); |
| } |
| DEFINE_TRACE(MainThreadWorklet) { |
| - visitor->Trace(resolver_map_); |
| + visitor->Trace(pending_tasks_map_); |
| Worklet::Trace(visitor); |
| } |