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); |
} |