blob: 3b8b0fa4782e6a800049029bf4dbaaf721ed541e [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <memory>
#include "base/macros.h"
#include "third_party/blink/renderer/core/css/css_syntax_definition.h"
#include "third_party/blink/renderer/core/workers/worklet.h"
#include "third_party/blink/renderer/modules/csspaint/document_paint_definition.h"
#include "third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope_proxy.h"
#include "third_party/blink/renderer/modules/csspaint/paint_worklet_pending_generator_registry.h"
#include "third_party/blink/renderer/modules/csspaint/paint_worklet_proxy_client.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
namespace blink {
class CSSPaintImageGeneratorImpl;
// Manages a paint worklet:
class MODULES_EXPORT PaintWorklet : public Worklet,
public Supplement<LocalDOMWindow> {
static const char kSupplementName[];
// At this moment, paint worklet allows at most two global scopes at any time.
static const wtf_size_t kNumGlobalScopesPerThread;
static PaintWorklet* From(LocalDOMWindow&);
explicit PaintWorklet(LocalFrame*);
~PaintWorklet() override;
void AddPendingGenerator(const String& name, CSSPaintImageGeneratorImpl*);
// The |container_size| is without subpixel snapping.
scoped_refptr<Image> Paint(const String& name,
const ImageResourceObserver&,
const FloatSize& container_size,
const CSSStyleValueVector*,
float device_scale_factor);
int WorkletId() const { return worklet_id_; }
void Trace(blink::Visitor*) override;
// The DocumentDefinitionMap tracks definitions registered via
// registerProperty; definitions are only considered valid once all global
// scopes have registered the same definition for the same thread.
typedef HashMap<String, std::unique_ptr<DocumentPaintDefinition>>
DocumentDefinitionMap& GetDocumentDefinitionMap() {
return document_definition_map_;
// Used for main-thread CSS Paint. Registers a definition for a given painter,
// ensuring that the same CSSPaintDefinition is registered on all global
// scopes.
void RegisterCSSPaintDefinition(const String& name,
// Used for off-thread CSS Paint. In this mode we are not responsible for
// tracking whether a definition is valid - this method should only be called
// once all global scopes have registered the same |DocumentPaintDefinition|
// for the same |name|.
void RegisterMainThreadDocumentPaintDefinition(
const String& name,
Vector<CSSPropertyID> native_properties,
Vector<String> custom_properties,
Vector<CSSSyntaxDefinition> input_argument_types,
double alpha);
HeapVector<Member<WorkletGlobalScopeProxy>>& GetGlobalScopesForTesting() {
return proxies_;
void AddGlobalScopeForTesting() { proxies_.push_back(CreateGlobalScope()); }
bool NeedsToCreateGlobalScopeForTesting() {
return NeedsToCreateGlobalScope();
void SetProxyClientForTesting(PaintWorkletProxyClient* proxy_client) {
proxy_client_ = proxy_client;
void ResetIsPaintOffThreadForTesting();
// Since paint worklet has more than one global scope, we MUST override this
// function and provide our own selection logic.
wtf_size_t SelectGlobalScope() final;
wtf_size_t GetActiveGlobalScopeForTesting() { return active_global_scope_; }
friend class PaintWorkletTest;
// Implements Worklet.
bool NeedsToCreateGlobalScope() final;
WorkletGlobalScopeProxy* CreateGlobalScope() final;
// This function calculates the number of paints to use before switching
// global scopes.
virtual int GetPaintsBeforeSwitching();
// This function calculates the next global scope to switch to.
virtual wtf_size_t SelectNewGlobalScope();
Member<PaintWorkletPendingGeneratorRegistry> pending_generator_registry_;
// Used for both main and off-thread CSS Paint.
// For the main thread, this map tracks the definitions created on the main
// thread, and ensures that all global scopes have the same definition.
// For the off thread case, both the worklet and main thread have this map.
// The worklet version is responsible for verifying that all global scopes
// have the same definition, and the main thread version relies on that.
// The value of an entry being nullptr means that it is an invalid definition.
DocumentDefinitionMap document_definition_map_;
// The last document paint frame a paint worklet painted on. This is used to
// tell when we begin painting on a new frame.
size_t active_frame_count_ = 0u;
// The current global scope being used for painting.
wtf_size_t active_global_scope_ = 0u;
// The number of paint calls remaining before Paint will select a new global
// scope. SelectGlobalScope resets this at the beginning of each frame.
int paints_before_switching_global_scope_;
// An atomic sequence number to ensure that it is unique for each paint
// worklet. This id is integrated in the PaintWorkletInput which will be used
// in PaintWorkletPaintDispatcher::Paint, to identify the right painter, to
// paint the image.
int worklet_id_;
// The proxy client associated with this PaintWorklet. We keep a reference in
// to ensure that all global scopes get the same proxy client.
Member<PaintWorkletProxyClient> proxy_client_;
// When running layout test, paint worklet has to be on the main thread
// because "enable-threaded-compositing" is off by default. However, some unit
// tests may be testing the functionality of the APIs when the paint worklet
// is off the main thread.
bool is_paint_off_thread_;
} // namespace blink