[Code Health] Clarify PaintWorkletPaintDispatcher behaviour

This CL adds some documentation for PaintWorkletPaintDispatcher, and
also changes up the |painter_map_| to allow direct lookup using the
worklet id.

Bug: None
Change-Id: I4f60ddce561b9fbc415f12f7f0bfcdd7a2c173d6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1625462
Reviewed-by: Xida Chen <xidachen@chromium.org>
Reviewed-by: Robert Flack <flackr@chromium.org>
Commit-Queue: Stephen McGruer <smcgruer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#662634}
diff --git a/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client.cc b/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client.cc
index 3868da7b..8b9a922 100644
--- a/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client.cc
+++ b/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client.cc
@@ -23,22 +23,27 @@
     "PaintWorkletProxyClient";
 
 // static
+PaintWorkletProxyClient* PaintWorkletProxyClient::From(WorkerClients* clients) {
+  return Supplement<WorkerClients>::From<PaintWorkletProxyClient>(clients);
+}
+
+// static
 PaintWorkletProxyClient* PaintWorkletProxyClient::Create(Document* document,
                                                          int worklet_id) {
   WebLocalFrameImpl* local_frame =
       WebLocalFrameImpl::FromFrame(document->GetFrame());
   PaintWorklet* paint_worklet = PaintWorklet::From(*document->domWindow());
-  scoped_refptr<PaintWorkletPaintDispatcher> compositor_painter_dispatcher =
+  scoped_refptr<PaintWorkletPaintDispatcher> compositor_paint_dispatcher =
       local_frame->LocalRootFrameWidget()->EnsureCompositorPaintDispatcher();
   return MakeGarbageCollected<PaintWorkletProxyClient>(
-      worklet_id, paint_worklet, std::move(compositor_painter_dispatcher));
+      worklet_id, paint_worklet, std::move(compositor_paint_dispatcher));
 }
 
 PaintWorkletProxyClient::PaintWorkletProxyClient(
     int worklet_id,
     PaintWorklet* paint_worklet,
-    scoped_refptr<PaintWorkletPaintDispatcher> compositor_paintee)
-    : compositor_paintee_(std::move(compositor_paintee)),
+    scoped_refptr<PaintWorkletPaintDispatcher> paint_dispatcher)
+    : paint_dispatcher_(std::move(paint_dispatcher)),
       worklet_id_(worklet_id),
       state_(RunState::kUninitialized),
       main_thread_runner_(Thread::MainThread()->GetTaskRunner()),
@@ -46,12 +51,6 @@
   DCHECK(IsMainThread());
 }
 
-void PaintWorkletProxyClient::Trace(blink::Visitor* visitor) {
-  visitor->Trace(document_definition_map_);
-  Supplement<WorkerClients>::Trace(visitor);
-  PaintWorkletPainter::Trace(visitor);
-}
-
 void PaintWorkletProxyClient::AddGlobalScope(WorkletGlobalScope* global_scope) {
   DCHECK(global_scope);
   DCHECK(global_scope->IsContextThread());
@@ -66,14 +65,14 @@
     return;
   }
 
-  // All the global scopes that share a single PaintWorkletProxyClient are
-  // running on the same thread, and so we can just grab the task runner from
-  // the last one to call this function and use that.
+  // All the global scopes that share a single PaintWorkletProxyClient run on
+  // the same thread with the same scheduler. As such we can just grab a task
+  // runner from the last one to register.
   scoped_refptr<base::SingleThreadTaskRunner> global_scope_runner =
       global_scope->GetThread()->GetTaskRunner(TaskType::kMiscPlatformAPI);
   state_ = RunState::kWorking;
 
-  compositor_paintee_->RegisterPaintWorkletPainter(this, global_scope_runner);
+  paint_dispatcher_->RegisterPaintWorkletPainter(this, global_scope_runner);
 }
 
 void PaintWorkletProxyClient::RegisterCSSPaintDefinition(
@@ -122,9 +121,9 @@
 
 void PaintWorkletProxyClient::Dispose() {
   if (state_ == RunState::kWorking) {
-    compositor_paintee_->UnregisterPaintWorkletPainter(this);
+    paint_dispatcher_->UnregisterPaintWorkletPainter(worklet_id_);
   }
-  compositor_paintee_ = nullptr;
+  paint_dispatcher_ = nullptr;
 
   state_ = RunState::kDisposed;
 
@@ -133,6 +132,12 @@
   global_scopes_.clear();
 }
 
+void PaintWorkletProxyClient::Trace(blink::Visitor* visitor) {
+  visitor->Trace(document_definition_map_);
+  Supplement<WorkerClients>::Trace(visitor);
+  PaintWorkletPainter::Trace(visitor);
+}
+
 sk_sp<PaintRecord> PaintWorkletProxyClient::Paint(
     CompositorPaintWorkletInput* compositor_input) {
   // TODO: Can this happen? We don't register till all are here.
@@ -162,11 +167,6 @@
                            style_map, nullptr);
 }
 
-// static
-PaintWorkletProxyClient* PaintWorkletProxyClient::From(WorkerClients* clients) {
-  return Supplement<WorkerClients>::From<PaintWorkletProxyClient>(clients);
-}
-
 void ProvidePaintWorkletProxyClientTo(WorkerClients* clients,
                                       PaintWorkletProxyClient* client) {
   clients->ProvideSupplement(client);
diff --git a/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client.h b/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client.h
index 9657633..4d4687177 100644
--- a/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client.h
+++ b/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client.h
@@ -18,12 +18,14 @@
 
 class WorkletGlobalScope;
 
-// Mediates between a worklet-thread bound PaintWorkletGlobalScope and its
-// associated dispatchers. A PaintWorkletProxyClient is associated with a single
-// global scope and one dispatcher to the compositor thread.
+// Mediates between the (multiple) PaintWorkletGlobalScopes on the worklet
+// thread and the (single) PaintWorkletPaintDispatcher on the non-worklet
+// threads. PaintWorkletProxyClient is responsible both for informing the
+// dispatcher about its existence once all global scopes are registered, as well
+// as choosing the global scope to use for any given paint request.
 //
-// This is constructed on the main thread but it is used in the worklet backing
-// thread.
+// This class is constructed on the main thread but it is used in the worklet
+// backing thread.
 class MODULES_EXPORT PaintWorkletProxyClient
     : public GarbageCollectedFinalized<PaintWorkletProxyClient>,
       public Supplement<WorkerClients>,
@@ -32,8 +34,13 @@
   DISALLOW_COPY_AND_ASSIGN(PaintWorkletProxyClient);
 
  public:
+  // blink::Supplement hook to retrieve the PaintWorkletProxyClient for a given
+  // WorkerClients.
   static const char kSupplementName[];
+  static PaintWorkletProxyClient* From(WorkerClients*);
 
+  // Create the PaintWorkletProxyClient for a given PaintWorklet, represented by
+  // its unique |worklet_id|.
   static PaintWorkletProxyClient* Create(Document*, int worklet_id);
 
   PaintWorkletProxyClient(
@@ -42,26 +49,31 @@
       scoped_refptr<PaintWorkletPaintDispatcher> compositor_paintee);
   ~PaintWorkletProxyClient() override = default;
 
-  void Trace(blink::Visitor*) override;
-
-  // PaintWorkletPainter implementation
+  // PaintWorkletPainter implementation.
   int GetWorkletId() const override { return worklet_id_; }
   sk_sp<PaintRecord> Paint(CompositorPaintWorkletInput*) override;
 
+  // Add a global scope to the PaintWorkletProxyClient.
   virtual void AddGlobalScope(WorkletGlobalScope*);
-  const Vector<CrossThreadPersistent<PaintWorkletGlobalScope>>&
-  GetGlobalScopesForTesting() const {
-    return global_scopes_;
-  }
 
+  // Register a paint definition for this PaintWorklet.
+  // See https://drafts.css-houdini.org/css-paint-api-1/#paint-definition
   void RegisterCSSPaintDefinition(const String& name,
                                   CSSPaintDefinition*,
                                   ExceptionState&);
 
+  // Dispose of the PaintWorkletProxyClient. Called when the worklet global
+  // scopes are being torn down. May be called once per global scope - calls
+  // after the first have no effect.
   void Dispose();
 
-  static PaintWorkletProxyClient* From(WorkerClients*);
+  void Trace(blink::Visitor*) override;
 
+  // Hooks for testing.
+  const Vector<CrossThreadPersistent<PaintWorkletGlobalScope>>&
+  GetGlobalScopesForTesting() const {
+    return global_scopes_;
+  }
   const HeapHashMap<String, Member<DocumentPaintDefinition>>&
   DocumentDefinitionMapForTesting() const {
     return document_definition_map_;
@@ -81,16 +93,38 @@
   FRIEND_TEST_ALL_PREFIXES(PaintWorkletProxyClientTest,
                            PaintWorkletProxyClientConstruction);
 
-  scoped_refptr<PaintWorkletPaintDispatcher> compositor_paintee_;
+  // The |paint_dispatcher_| is shared between all PaintWorklets on the same
+  // Renderer process, and is responsible for dispatching paint calls from the
+  // non-worklet threads to the correct PaintWorkletProxyClient on its worklet
+  // thread. PaintWorkletProxyClient requires a reference to the dispatcher in
+  // order to register and unregister itself.
+  scoped_refptr<PaintWorkletPaintDispatcher> paint_dispatcher_;
+
+  // The unique id for the PaintWorklet that this class is a proxy client for.
   const int worklet_id_;
+
+  // The set of global scopes registered for this PaintWorklet. Multiple global
+  // scopes are used to enforce statelessness - paint instances may have their
+  // global scope changed at random which means they cannot easily store state.
   Vector<CrossThreadPersistent<PaintWorkletGlobalScope>> global_scopes_;
+
+  // The current state of the proxy client. PaintWorkletProxyClient is initially
+  // uninitialized. Once all global scopes are registered, it is considered
+  // working - unless it is disposed of before this happens in which case it
+  // stays in the disposed state.
   enum RunState { kUninitialized, kWorking, kDisposed } state_;
 
-  // Stores the definitions for each paint that is registered.
+  // Stores the paint definitions as they are registered from the global scopes.
+  // For a given named paint definition, all global scopes must report the same
+  // DocumentPaintDefinition or the definition is invalid. Additionally we
+  // cannot tell the main thread about a paint definition until all global
+  // scopes have registered it.
   HeapHashMap<String, Member<DocumentPaintDefinition>> document_definition_map_;
 
-  // Used for OffMainThreadPaintWorklet; we post to the main-thread PaintWorklet
-  // instance to store the definitions for each paint that is registered.
+  // The main thread needs to know about registered paint definitions so that it
+  // can invalidate any associated paint objects and correctly create the paint
+  // instance input state for the object, etc. We communicate with it via a
+  // handle to the PaintWorklet called via a stored task runner.
   scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner_;
   CrossThreadWeakPersistent<PaintWorklet> paint_worklet_;
 };
diff --git a/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client_test.cc b/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client_test.cc
index 6969ff34..40fc1d8 100644
--- a/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client_test.cc
+++ b/third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client_test.cc
@@ -108,7 +108,7 @@
   PaintWorkletProxyClient* proxy_client =
       MakeGarbageCollected<PaintWorkletProxyClient>(1, nullptr, nullptr);
   EXPECT_EQ(proxy_client->worklet_id_, 1);
-  EXPECT_EQ(proxy_client->compositor_paintee_, nullptr);
+  EXPECT_EQ(proxy_client->paint_dispatcher_, nullptr);
 
   scoped_refptr<PaintWorkletPaintDispatcher> dispatcher =
       base::MakeRefCounted<PaintWorkletPaintDispatcher>();
@@ -116,7 +116,7 @@
   proxy_client = MakeGarbageCollected<PaintWorkletProxyClient>(
       1, nullptr, std::move(dispatcher));
   EXPECT_EQ(proxy_client->worklet_id_, 1);
-  EXPECT_NE(proxy_client->compositor_paintee_, nullptr);
+  EXPECT_NE(proxy_client->paint_dispatcher_, nullptr);
 }
 
 void RunAddGlobalScopesTestOnWorklet(
diff --git a/third_party/blink/renderer/platform/graphics/paint_worklet_paint_dispatcher.cc b/third_party/blink/renderer/platform/graphics/paint_worklet_paint_dispatcher.cc
index a523492f..419fce5 100644
--- a/third_party/blink/renderer/platform/graphics/paint_worklet_paint_dispatcher.cc
+++ b/third_party/blink/renderer/platform/graphics/paint_worklet_paint_dispatcher.cc
@@ -49,21 +49,20 @@
   TRACE_EVENT0("cc",
                "PaintWorkletPaintDispatcher::RegisterPaintWorkletPainter");
 
-  DCHECK(painter);
+  int worklet_id = painter->GetWorkletId();
   MutexLocker lock(painter_map_mutex_);
-  DCHECK(painter_map_.find(painter) == painter_map_.end());
-  painter_map_.insert(painter, painter_runner);
+  DCHECK(painter_map_.find(worklet_id) == painter_map_.end());
+  painter_map_.insert(worklet_id, std::make_pair(painter, painter_runner));
 }
 
 void PaintWorkletPaintDispatcher::UnregisterPaintWorkletPainter(
-    PaintWorkletPainter* painter) {
+    int worklet_id) {
   TRACE_EVENT0("cc",
                "PaintWorkletPaintDispatcher::"
                "UnregisterPaintWorkletPainter");
-  DCHECK(painter);
   MutexLocker lock(painter_map_mutex_);
-  DCHECK(painter_map_.find(painter) != painter_map_.end());
-  painter_map_.erase(painter);
+  DCHECK(painter_map_.find(worklet_id) != painter_map_.end());
+  painter_map_.erase(worklet_id);
 }
 
 // TODO(xidachen): we should bundle all PaintWorkletInputs and send them to the
@@ -86,27 +85,25 @@
 
   base::WaitableEvent done_event;
 
-  for (auto& pair : copied_painter_map) {
-    if (pair.key->GetWorkletId() != input->WorkletId())
-      continue;
-    PaintWorkletPainter* painter = pair.key;
-    scoped_refptr<base::SingleThreadTaskRunner> task_runner = pair.value;
+  auto it = copied_painter_map.find(input->WorkletId());
+  if (it == copied_painter_map.end())
+    return output;
 
-    DCHECK(!task_runner->BelongsToCurrentThread());
-    std::unique_ptr<AutoSignal> done =
-        std::make_unique<AutoSignal>(&done_event);
+  PaintWorkletPainter* painter = it->value.first;
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner = it->value.second;
+  DCHECK(!task_runner->BelongsToCurrentThread());
+  std::unique_ptr<AutoSignal> done = std::make_unique<AutoSignal>(&done_event);
 
-    PostCrossThreadTask(
-        *task_runner, FROM_HERE,
-        CrossThreadBindOnce(
-            [](PaintWorkletPainter* painter, cc::PaintWorkletInput* input,
-               std::unique_ptr<AutoSignal> completion,
-               sk_sp<cc::PaintRecord>* output) {
-              *output = painter->Paint(input);
-            },
-            WrapCrossThreadPersistent(painter), CrossThreadUnretained(input),
-            WTF::Passed(std::move(done)), CrossThreadUnretained(&output)));
-  }
+  PostCrossThreadTask(
+      *task_runner, FROM_HERE,
+      CrossThreadBindOnce(
+          [](PaintWorkletPainter* painter, cc::PaintWorkletInput* input,
+             std::unique_ptr<AutoSignal> completion,
+             sk_sp<cc::PaintRecord>* output) {
+            *output = painter->Paint(input);
+          },
+          WrapCrossThreadPersistent(painter), CrossThreadUnretained(input),
+          WTF::Passed(std::move(done)), CrossThreadUnretained(&output)));
 
   done_event.Wait();
 
diff --git a/third_party/blink/renderer/platform/graphics/paint_worklet_paint_dispatcher.h b/third_party/blink/renderer/platform/graphics/paint_worklet_paint_dispatcher.h
index 6364325..bb18c17 100644
--- a/third_party/blink/renderer/platform/graphics/paint_worklet_paint_dispatcher.h
+++ b/third_party/blink/renderer/platform/graphics/paint_worklet_paint_dispatcher.h
@@ -20,9 +20,17 @@
 
 namespace blink {
 
-// The dispatcher receives JS paint callback from the compositor, and dispatch
-// the callback to the painter (on the paint worklet thread) that is associated
-// with the given paint image.
+// PaintWorkletPaintDispatcher is responsible for mediating between the raster
+// threads and the PaintWorklet thread(s). It receives requests from raster
+// threads to paint a paint class instance represented by a PaintWorkletInput,
+// dispatches the input to the appropriate PaintWorklet, synchronously receives
+// the result, and passes it back to the raster thread.
+//
+// Each PaintWorklet (there is one per frame, either same-origin or
+// same-process-cross-origin) has a backing thread, which may be shared between
+// worklets, and a scheduler, which is not shared. All PaintWorklets for a
+// single renderer process share one PaintWorkletPaintDispatcher on the
+// compositor side.
 class PLATFORM_EXPORT PaintWorkletPaintDispatcher
     : public ThreadSafeRefCounted<PaintWorkletPaintDispatcher> {
  public:
@@ -32,30 +40,39 @@
 
   PaintWorkletPaintDispatcher() = default;
 
-  // Interface for use by the PaintWorklet thread(s) to request calls.
-  // (To the given Painter on the given TaskRunner.)
-  void RegisterPaintWorkletPainter(
-      PaintWorkletPainter*,
-      scoped_refptr<base::SingleThreadTaskRunner> mutator_runner);
-
-  void UnregisterPaintWorkletPainter(PaintWorkletPainter*);
-
+  // Dispatches a single paint class instance - represented by a
+  // PaintWorkletInput - to the appropriate PaintWorklet thread, and blocks
+  // until it receives the result.
   sk_sp<cc::PaintRecord> Paint(cc::PaintWorkletInput*);
 
+  // Register and unregister a PaintWorklet (represented in this context by a
+  // PaintWorkletPainter). A given PaintWorklet is registered once all its
+  // global scopes have been created, and is usually only unregistered when the
+  // associated PaintWorklet thread is being torn down.
+  //
+  // The passed in PaintWorkletPainter* should only be used on the given
+  // base::SingleThreadTaskRunner.
+  using PaintWorkletId = int;
+  void RegisterPaintWorkletPainter(PaintWorkletPainter*,
+                                   scoped_refptr<base::SingleThreadTaskRunner>);
+  void UnregisterPaintWorkletPainter(PaintWorkletId);
+
   using PaintWorkletPainterToTaskRunnerMap =
-      HashMap<CrossThreadPersistent<PaintWorkletPainter>,
-              scoped_refptr<base::SingleThreadTaskRunner>>;
+      HashMap<PaintWorkletId,
+              std::pair<CrossThreadPersistent<PaintWorkletPainter>,
+                        scoped_refptr<base::SingleThreadTaskRunner>>>;
   const PaintWorkletPainterToTaskRunnerMap& PainterMapForTesting() const {
     return painter_map_;
   }
 
  private:
-  // We can have more than one task-runner because using a worklet inside a
-  // frame with a different origin causes a new global scope => new thread.
+  // This class handles paint class instances for multiple PaintWorklets. These
+  // are disambiguated via the PaintWorklets unique id; this map exists to do
+  // that disambiguation.
   PaintWorkletPainterToTaskRunnerMap painter_map_;
 
   // The (Un)registerPaintWorkletPainter comes from the worklet thread, and the
-  // Paint call is initiated from the raster threads, this mutex ensures that
+  // Paint call is initiated from the raster threads - this mutex ensures that
   // accessing / updating the |painter_map_| is thread safe.
   Mutex painter_map_mutex_;