blob: e27b374024f1bd426b253916549c3e473d6281b9 [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 "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/core/css/css_computed_style_declaration.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/core/layout/layout_object.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/bindings/v8_object_constructor.h"
#include "third_party/blink/renderer/platform/graphics/paint_generated_image.h"
namespace blink {
namespace {
FloatSize GetSpecifiedSize(const FloatSize& 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 FloatSize(un_zoom_fn(size.Width()), un_zoom_fn(size.Height()));
}
} // namespace
CSSPaintDefinition* CSSPaintDefinition::Create(
ScriptState* script_state,
v8::Local<v8::Function> constructor,
v8::Local<v8::Function> paint,
const Vector<CSSPropertyID>& native_invalidation_properties,
const Vector<AtomicString>& custom_invalidation_properties,
const Vector<CSSSyntaxDescriptor>& input_argument_types,
const PaintRenderingContext2DSettings* context_settings) {
return MakeGarbageCollected<CSSPaintDefinition>(
script_state, constructor, paint, native_invalidation_properties,
custom_invalidation_properties, input_argument_types, context_settings);
}
CSSPaintDefinition::CSSPaintDefinition(
ScriptState* script_state,
v8::Local<v8::Function> constructor,
v8::Local<v8::Function> paint,
const Vector<CSSPropertyID>& native_invalidation_properties,
const Vector<AtomicString>& custom_invalidation_properties,
const Vector<CSSSyntaxDescriptor>& input_argument_types,
const PaintRenderingContext2DSettings* context_settings)
: script_state_(script_state),
constructor_(script_state->GetIsolate(), constructor),
paint_(script_state->GetIsolate(), paint),
did_call_constructor_(false),
context_settings_(context_settings) {
native_invalidation_properties_ = native_invalidation_properties;
custom_invalidation_properties_ = custom_invalidation_properties;
input_argument_types_ = input_argument_types;
}
CSSPaintDefinition::~CSSPaintDefinition() = default;
scoped_refptr<Image> CSSPaintDefinition::Paint(
const ImageResourceObserver& client,
const FloatSize& container_size,
const CSSStyleValueVector* paint_arguments) {
// TODO: Break dependency on LayoutObject. Passing the Node should work.
const LayoutObject& layout_object = static_cast<const LayoutObject&>(client);
float zoom = layout_object.StyleRef().EffectiveZoom();
const FloatSize specified_size = GetSpecifiedSize(container_size, zoom);
ScriptState::Scope scope(script_state_);
MaybeCreatePaintInstance();
v8::Isolate* isolate = script_state_->GetIsolate();
v8::Local<v8::Value> instance = instance_.NewLocal(isolate);
// We may have failed to create an instance class, in which case produce an
// invalid image.
if (IsUndefinedOrNull(instance))
return nullptr;
DCHECK(layout_object.GetNode());
CanvasColorParams color_params;
if (!context_settings_->alpha()) {
color_params.SetOpacityMode(kOpaque);
}
// Do subpixel snapping for the |container_size|.
PaintRenderingContext2D* rendering_context = PaintRenderingContext2D::Create(
RoundedIntSize(container_size), color_params, context_settings_, zoom);
PaintSize* paint_size = PaintSize::Create(specified_size);
StylePropertyMapReadOnly* style_map =
MakeGarbageCollected<PrepopulatedComputedStylePropertyMap>(
layout_object.GetDocument(), layout_object.StyleRef(),
layout_object.GetNode(), native_invalidation_properties_,
custom_invalidation_properties_);
Vector<v8::Local<v8::Value>, 4> argv;
if (paint_arguments) {
argv = {
ToV8(rendering_context, script_state_->GetContext()->Global(), isolate),
ToV8(paint_size, script_state_->GetContext()->Global(), isolate),
ToV8(style_map, script_state_->GetContext()->Global(), isolate),
ToV8(*paint_arguments, script_state_->GetContext()->Global(), isolate)};
} else {
argv = {
ToV8(rendering_context, script_state_->GetContext()->Global(), isolate),
ToV8(paint_size, script_state_->GetContext()->Global(), isolate),
ToV8(style_map, script_state_->GetContext()->Global(), isolate)};
}
v8::Local<v8::Function> paint = paint_.NewLocal(isolate);
v8::TryCatch block(isolate);
block.SetVerbose(true);
V8ScriptRunner::CallFunction(paint, ExecutionContext::From(script_state_),
instance, argv.size(), argv.data(), isolate);
// The paint function may have produced an error, in which case produce an
// invalid image.
if (block.HasCaught()) {
return nullptr;
}
return PaintGeneratedImage::Create(rendering_context->GetRecord(),
container_size);
}
void CSSPaintDefinition::MaybeCreatePaintInstance() {
if (did_call_constructor_)
return;
DCHECK(instance_.IsEmpty());
v8::Isolate* isolate = script_state_->GetIsolate();
v8::Local<v8::Function> constructor = constructor_.NewLocal(isolate);
DCHECK(!IsUndefinedOrNull(constructor));
v8::Local<v8::Value> paint_instance;
if (V8ScriptRunner::CallAsConstructor(
isolate, constructor, ExecutionContext::From(script_state_), 0, {})
.ToLocal(&paint_instance))
instance_.Set(isolate, paint_instance);
did_call_constructor_ = true;
}
void CSSPaintDefinition::Trace(Visitor* visitor) {
visitor->Trace(constructor_.Cast<v8::Value>());
visitor->Trace(paint_.Cast<v8::Value>());
visitor->Trace(instance_);
visitor->Trace(context_settings_);
visitor->Trace(script_state_);
}
} // namespace blink