blob: 60e1015a7d9ae7324d85436301bfe0a1d937ec87 [file] [log] [blame]
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/modules/csspaint/css_paint_definition.h"
#include <memory>
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_no_argument_constructor.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_paint_callback.h"
#include "third_party/blink/renderer/core/css/css_computed_style_declaration.h"
#include "third_party/blink/renderer/core/css/cssom/cross_thread_color_value.h"
#include "third_party/blink/renderer/core/css/cssom/cross_thread_unit_value.h"
#include "third_party/blink/renderer/core/css/cssom/css_paint_worklet_input.h"
#include "third_party/blink/renderer/core/css/cssom/prepopulated_computed_style_property_map.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.h"
#include "third_party/blink/renderer/modules/csspaint/paint_size.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/bindings/v8_binding_macros.h"
#include "third_party/blink/renderer/platform/graphics/paint_generated_image.h"
#include "third_party/blink/renderer/platform/wtf/casting.h"
namespace blink {
namespace {
gfx::SizeF GetSpecifiedSize(const gfx::SizeF& size, float zoom) {
float un_zoom_factor = 1 / zoom;
auto un_zoom_fn = [un_zoom_factor](float a) -> float {
return a * un_zoom_factor;
};
return gfx::SizeF(un_zoom_fn(size.width()), un_zoom_fn(size.height()));
}
} // namespace
CSSPaintDefinition::CSSPaintDefinition(
ScriptState* script_state,
V8NoArgumentConstructor* constructor,
V8PaintCallback* paint,
const Vector<CSSPropertyID>& native_invalidation_properties,
const Vector<AtomicString>& custom_invalidation_properties,
const Vector<CSSSyntaxDefinition>& input_argument_types,
const PaintRenderingContext2DSettings* context_settings,
PaintWorkletGlobalScope* global_scope)
: script_state_(script_state),
constructor_(constructor),
paint_(paint),
did_call_constructor_(false),
context_settings_(context_settings),
global_scope_(global_scope) {
native_invalidation_properties_ = native_invalidation_properties;
custom_invalidation_properties_ = custom_invalidation_properties;
input_argument_types_ = input_argument_types;
}
CSSPaintDefinition::~CSSPaintDefinition() = default;
// PaintDefinition override
PaintRecord CSSPaintDefinition::Paint(
const CompositorPaintWorkletInput* compositor_input,
const CompositorPaintWorkletJob::AnimatedPropertyValues&
animated_property_values) {
const CSSPaintWorkletInput* input =
To<CSSPaintWorkletInput>(compositor_input);
PaintWorkletStylePropertyMap* style_map =
MakeGarbageCollected<PaintWorkletStylePropertyMap>(input->StyleMapData());
CSSStyleValueVector paint_arguments;
for (const auto& style_value : input->ParsedInputArguments()) {
paint_arguments.push_back(style_value->ToCSSStyleValue());
}
ApplyAnimatedPropertyOverrides(style_map, animated_property_values);
return Paint(input->GetSize(), input->EffectiveZoom(), style_map,
&paint_arguments);
}
PaintRecord CSSPaintDefinition::Paint(
const gfx::SizeF& container_size,
float zoom,
StylePropertyMapReadOnly* style_map,
const CSSStyleValueVector* paint_arguments) {
const gfx::SizeF specified_size = GetSpecifiedSize(container_size, zoom);
ScriptState::Scope scope(script_state_);
MaybeCreatePaintInstance();
// We may have failed to create an instance, in which case produce an
// invalid image.
if (instance_.IsEmpty())
return PaintRecord();
v8::Isolate* isolate = script_state_->GetIsolate();
// Do subpixel snapping for the |container_size|.
auto* rendering_context = MakeGarbageCollected<PaintRenderingContext2D>(
ToRoundedSize(container_size), context_settings_, zoom,
global_scope_->GetTaskRunner(TaskType::kMiscPlatformAPI), global_scope_);
PaintSize* paint_size = MakeGarbageCollected<PaintSize>(specified_size);
CSSStyleValueVector empty_paint_arguments;
if (!paint_arguments)
paint_arguments = &empty_paint_arguments;
v8::TryCatch try_catch(isolate);
try_catch.SetVerbose(true);
// The paint function may have produced an error, in which case produce an
// invalid image.
if (paint_
->Invoke(instance_.Get(isolate), rendering_context, paint_size,
style_map, *paint_arguments)
.IsNothing()) {
return PaintRecord();
}
return rendering_context->GetRecord();
}
void CSSPaintDefinition::ApplyAnimatedPropertyOverrides(
PaintWorkletStylePropertyMap* style_map,
const CompositorPaintWorkletJob::AnimatedPropertyValues&
animated_property_values) {
for (const auto& property_value : animated_property_values) {
DCHECK(property_value.second.has_value());
String property_name(
property_value.first.custom_property_name.value().c_str());
DCHECK(style_map->StyleMapData().Contains(property_name));
CrossThreadStyleValue* old_value =
style_map->StyleMapData().at(property_name);
switch (old_value->GetType()) {
case CrossThreadStyleValue::StyleValueType::kUnitType: {
DCHECK(property_value.second.float_value);
std::unique_ptr<CrossThreadUnitValue> new_value =
std::make_unique<CrossThreadUnitValue>(
property_value.second.float_value.value(),
DynamicTo<CrossThreadUnitValue>(old_value)->GetUnitType());
style_map->StyleMapData().Set(property_name, std::move(new_value));
break;
}
case CrossThreadStyleValue::StyleValueType::kColorType: {
DCHECK(property_value.second.color_value);
std::unique_ptr<CrossThreadColorValue> new_value =
std::make_unique<CrossThreadColorValue>(Color::FromSkColor4f(
property_value.second.color_value.value()));
style_map->StyleMapData().Set(property_name, std::move(new_value));
break;
}
default:
NOTREACHED();
break;
}
}
}
void CSSPaintDefinition::MaybeCreatePaintInstance() {
if (did_call_constructor_)
return;
did_call_constructor_ = true;
DCHECK(instance_.IsEmpty());
ScriptValue paint_instance;
if (!constructor_->Construct().To(&paint_instance))
return;
instance_.Reset(constructor_->GetIsolate(), paint_instance.V8Value());
}
void CSSPaintDefinition::Trace(Visitor* visitor) const {
visitor->Trace(constructor_);
visitor->Trace(paint_);
visitor->Trace(instance_);
visitor->Trace(context_settings_);
visitor->Trace(script_state_);
visitor->Trace(global_scope_);
PaintDefinition::Trace(visitor);
}
} // namespace blink