blob: d0435fa43d1f2295fca9f79752a1dc8641533739 [file] [log] [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_CSSPAINT_PAINT_WORKLET_PROXY_CLIENT_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_CSSPAINT_PAINT_WORKLET_PROXY_CLIENT_H_
#include "base/gtest_prod_util.h"
#include "base/task/single_thread_task_runner.h"
#include "third_party/blink/renderer/core/css/cssom/paint_worklet_input.h"
#include "third_party/blink/renderer/core/workers/worker_clients.h"
#include "third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/graphics/paint_worklet_paint_dispatcher.h"
#include "third_party/blink/renderer/platform/graphics/paint_worklet_painter.h"
#include "third_party/blink/renderer/platform/graphics/platform_paint_worklet_layer_painter.h"
#include "third_party/blink/renderer/platform/heap/cross_thread_handle.h"
namespace blink {
class DocumentPaintDefinition;
class NativePaintDefinition;
class PaintWorklet;
class WorkletGlobalScope;
class WorkerBackingThread;
// 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 class is constructed on the main thread but it is used in the worklet
// backing thread. The entire class is used for off-thread CSS Paint.
class MODULES_EXPORT PaintWorkletProxyClient
: public GarbageCollected<PaintWorkletProxyClient>,
public Supplement<WorkerClients>,
public PaintWorkletPainter {
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(LocalDOMWindow*, int worklet_id);
PaintWorkletProxyClient(
int worklet_id,
PaintWorklet*,
scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
base::WeakPtr<PaintWorkletPaintDispatcher> compositor_paintee,
scoped_refptr<base::SingleThreadTaskRunner> compositor_host_queue);
PaintWorkletProxyClient(const PaintWorkletProxyClient&) = delete;
PaintWorkletProxyClient& operator=(const PaintWorkletProxyClient&) = delete;
~PaintWorkletProxyClient() override = default;
// PaintWorkletPainter implementation.
int GetWorkletId() const override { return worklet_id_; }
PaintRecord Paint(const CompositorPaintWorkletInput*,
const CompositorPaintWorkletJob::AnimatedPropertyValues&
animated_property_values) override;
// Add a global scope to the PaintWorkletProxyClient.
virtual void AddGlobalScope(WorkletGlobalScope*);
// 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();
void Trace(Visitor*) const override;
// Hooks for testing.
const Vector<CrossThreadPersistent<PaintWorkletGlobalScope>>&
GetGlobalScopesForTesting() const {
return global_scopes_;
}
const HashMap<String, std::unique_ptr<DocumentPaintDefinition>>&
DocumentDefinitionMapForTesting() const {
return document_definition_map_;
}
scoped_refptr<base::SingleThreadTaskRunner> MainThreadTaskRunnerForTesting()
const {
return main_thread_runner_;
}
void SetMainThreadTaskRunnerForTesting(
scoped_refptr<base::SingleThreadTaskRunner> runner) {
main_thread_runner_ = runner;
}
double DevicePixelRatio() const { return device_pixel_ratio_; }
void RegisterForNativePaintWorklet(
WorkerBackingThread* thread,
NativePaintDefinition* definition,
PaintWorkletInput::PaintWorkletInputType type);
void UnregisterForNativePaintWorklet();
private:
friend class PaintWorkletGlobalScopeTest;
friend class PaintWorkletProxyClientTest;
FRIEND_TEST_ALL_PREFIXES(PaintWorkletProxyClientTest,
PaintWorkletProxyClientConstruction);
// Store the device pixel ratio here so it can be used off main thread
double device_pixel_ratio_;
// 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.
//
// PaintWorkletPaintDispatcher is only accessed on the compositor, so we store
// a base::SingleThreadTaskRunner to post to it.
base::WeakPtr<PaintWorkletPaintDispatcher> paint_dispatcher_;
scoped_refptr<base::SingleThreadTaskRunner> compositor_host_queue_;
// 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 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.
//
// The value of an entry being nullptr means that it is an invalid definition.
HashMap<String, std::unique_ptr<DocumentPaintDefinition>>
document_definition_map_;
// 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_;
CrossThreadWeakHandle<PaintWorklet> paint_worklet_;
HashMap<PaintWorkletInput::PaintWorkletInputType,
CrossThreadPersistent<NativePaintDefinition>>
native_definitions_;
};
void MODULES_EXPORT ProvidePaintWorkletProxyClientTo(WorkerClients*,
PaintWorkletProxyClient*);
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_CSSPAINT_PAINT_WORKLET_PROXY_CLIENT_H_