blob: 64ee0ed97d3856533d0be05f2a07a2907ba52797 [file] [log] [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "cc/paint/paint_filter.h"
#include <string>
#include <utility>
#include <vector>
#include "base/memory/values_equivalent.h"
#include "base/no_destructor.h"
#include "base/notreached.h"
#include "base/ranges/algorithm.h"
#include "base/types/optional_util.h"
#include "build/build_config.h"
#include "cc/paint/draw_image.h"
#include "cc/paint/filter_operations.h"
#include "cc/paint/image_provider.h"
#include "cc/paint/paint_image_builder.h"
#include "cc/paint/paint_op_writer.h"
#include "cc/paint/paint_record.h"
#include "cc/paint/scoped_raster_flags.h"
#include "third_party/skia/include/core/SkColorFilter.h"
#include "third_party/skia/include/core/SkColorSpace.h"
#include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/core/SkMatrix.h"
#include "third_party/skia/include/core/SkScalar.h"
#include "third_party/skia/include/core/SkShader.h"
#include "third_party/skia/include/core/SkString.h"
#include "third_party/skia/include/core/SkTileMode.h"
#include "third_party/skia/include/effects/SkImageFilters.h"
#include "third_party/skia/include/effects/SkPerlinNoiseShader.h"
#include "third_party/skia/include/effects/SkRuntimeEffect.h"
namespace cc {
namespace {
const bool kHasNoDiscardableImages = false;
template <typename T>
bool AreValuesEqualForTesting(const sk_sp<T>& a, const sk_sp<T>& b) {
return base::ValuesEquivalent(a, b, [](const T& x, const T& y) {
return x.EqualsForTesting(y); // IN-TEST
});
}
template <typename T>
bool AreEqualForTesting(const PaintFilter& a, const PaintFilter& b) {
return static_cast<const T&>(a).EqualsForTesting( // IN-TEST
static_cast<const T&>(b));
}
bool HasDiscardableImages(const sk_sp<PaintFilter>& filter) {
return filter ? filter->has_discardable_images() : false;
}
bool HasDiscardableImages(const sk_sp<PaintFilter>* const filters, int count) {
for (int i = 0; i < count; ++i) {
if (filters[i] && filters[i]->has_discardable_images())
return true;
}
return false;
}
sk_sp<PaintFilter> Snapshot(const sk_sp<PaintFilter>& filter,
ImageProvider* image_provider) {
if (!filter)
return nullptr;
return filter->SnapshotWithImages(image_provider);
}
} // namespace
PaintFilter::PaintFilter(Type type,
const CropRect* crop_rect,
bool has_discardable_images)
: type_(type), has_discardable_images_(has_discardable_images) {
if (crop_rect)
crop_rect_.emplace(*crop_rect);
}
PaintFilter::~PaintFilter() = default;
// static
std::string PaintFilter::TypeToString(Type type) {
switch (type) {
case Type::kNullFilter:
return "kNullFilter";
case Type::kColorFilter:
return "kColorFilter";
case Type::kBlur:
return "kBlur";
case Type::kDropShadow:
return "kDropShadow";
case Type::kMagnifier:
return "kMagnifier";
case Type::kCompose:
return "kCompose";
case Type::kAlphaThreshold:
return "kAlphaThreshold";
case Type::kXfermode:
return "kXfermode";
case Type::kArithmetic:
return "kArithmetic";
case Type::kMatrixConvolution:
return "kMatrixConvolution";
case Type::kDisplacementMapEffect:
return "kDisplacementMapEffect";
case Type::kImage:
return "kImage";
case Type::kPaintRecord:
return "kPaintRecord";
case Type::kMerge:
return "kMerge";
case Type::kMorphology:
return "kMorphology";
case Type::kOffset:
return "kOffset";
case Type::kTile:
return "kTile";
case Type::kTurbulence:
return "kTurbulence";
case Type::kShader:
return "kShader";
case Type::kMatrix:
return "kMatrix";
case Type::kLightingDistant:
return "kLightingDistant";
case Type::kLightingPoint:
return "kLightingPoint";
case Type::kLightingSpot:
return "kLightingSpot";
}
NOTREACHED();
return "Unknown";
}
const PaintFilter::CropRect* PaintFilter::GetCropRect() const {
return base::OptionalToPtr(crop_rect_);
}
size_t PaintFilter::BaseSerializedSize() const {
size_t total_size = 0u;
total_size += PaintOpWriter::SerializedSize(type_);
// Bool to indicate whether crop exists.
total_size += PaintOpWriter::SerializedSize<bool>();
if (crop_rect_) {
total_size += PaintOpWriter::SerializedSize(*crop_rect_);
}
return total_size;
}
sk_sp<PaintFilter> PaintFilter::SnapshotWithImages(
ImageProvider* image_provider) const {
if (!has_discardable_images_)
return sk_ref_sp<PaintFilter>(this);
return SnapshotWithImagesInternal(image_provider);
}
bool PaintFilter::EqualsForTesting(const PaintFilter& other) const {
if (type_ != other.type_) {
return false;
}
if (crop_rect_ != other.crop_rect_) {
return false;
}
switch (type_) {
case Type::kNullFilter:
return true;
case Type::kColorFilter:
return AreEqualForTesting<ColorFilterPaintFilter>(*this, other);
case Type::kBlur:
return AreEqualForTesting<BlurPaintFilter>(*this, other);
case Type::kDropShadow:
return AreEqualForTesting<DropShadowPaintFilter>(*this, other);
case Type::kMagnifier:
return AreEqualForTesting<MagnifierPaintFilter>(*this, other);
case Type::kCompose:
return AreEqualForTesting<ComposePaintFilter>(*this, other);
case Type::kAlphaThreshold:
return AreEqualForTesting<AlphaThresholdPaintFilter>(*this, other);
case Type::kXfermode:
return AreEqualForTesting<XfermodePaintFilter>(*this, other);
case Type::kArithmetic:
return AreEqualForTesting<ArithmeticPaintFilter>(*this, other);
case Type::kMatrixConvolution:
return AreEqualForTesting<MatrixConvolutionPaintFilter>(*this, other);
case Type::kDisplacementMapEffect:
return AreEqualForTesting<DisplacementMapEffectPaintFilter>(*this, other);
case Type::kImage:
return AreEqualForTesting<ImagePaintFilter>(*this, other);
case Type::kPaintRecord:
return AreEqualForTesting<RecordPaintFilter>(*this, other);
case Type::kMerge:
return AreEqualForTesting<MergePaintFilter>(*this, other);
case Type::kMorphology:
return AreEqualForTesting<MorphologyPaintFilter>(*this, other);
case Type::kOffset:
return AreEqualForTesting<OffsetPaintFilter>(*this, other);
case Type::kTile:
return AreEqualForTesting<TilePaintFilter>(*this, other);
case Type::kTurbulence:
return AreEqualForTesting<TurbulencePaintFilter>(*this, other);
case Type::kShader:
return AreEqualForTesting<ShaderPaintFilter>(*this, other);
case Type::kMatrix:
return AreEqualForTesting<MatrixPaintFilter>(*this, other);
case Type::kLightingDistant:
return AreEqualForTesting<LightingDistantPaintFilter>(*this, other);
case Type::kLightingPoint:
return AreEqualForTesting<LightingPointPaintFilter>(*this, other);
case Type::kLightingSpot:
return AreEqualForTesting<LightingSpotPaintFilter>(*this, other);
}
NOTREACHED();
return true;
}
ColorFilterPaintFilter::ColorFilterPaintFilter(sk_sp<ColorFilter> color_filter,
sk_sp<PaintFilter> input,
const CropRect* crop_rect)
: PaintFilter(kType, crop_rect, HasDiscardableImages(input)),
color_filter_(std::move(color_filter)),
input_(std::move(input)) {
cached_sk_filter_ = SkImageFilters::ColorFilter(
color_filter_ ? color_filter_->GetSkColorFilter() : nullptr,
GetSkFilter(input_.get()), crop_rect);
}
ColorFilterPaintFilter::~ColorFilterPaintFilter() = default;
size_t ColorFilterPaintFilter::SerializedSize() const {
base::CheckedNumeric<size_t> total_size = 0u;
total_size += BaseSerializedSize();
total_size += PaintOpWriter::SerializedSize(color_filter_.get());
total_size += PaintOpWriter::SerializedSize(input_.get());
return total_size.ValueOrDefault(0u);
}
sk_sp<PaintFilter> ColorFilterPaintFilter::SnapshotWithImagesInternal(
ImageProvider* image_provider) const {
return sk_make_sp<ColorFilterPaintFilter>(
color_filter_, Snapshot(input_, image_provider), GetCropRect());
}
bool ColorFilterPaintFilter::EqualsForTesting(
const ColorFilterPaintFilter& other) const {
return AreValuesEqualForTesting(color_filter_, // IN-TEST
other.color_filter_) &&
AreValuesEqualForTesting(input_, other.input_); // IN-TEST
}
BlurPaintFilter::BlurPaintFilter(SkScalar sigma_x,
SkScalar sigma_y,
SkTileMode tile_mode,
sk_sp<PaintFilter> input,
const CropRect* crop_rect)
: PaintFilter(kType, crop_rect, HasDiscardableImages(input)),
sigma_x_(sigma_x),
sigma_y_(sigma_y),
tile_mode_(tile_mode),
input_(std::move(input)) {
cached_sk_filter_ = SkImageFilters::Blur(
sigma_x, sigma_y, tile_mode_, GetSkFilter(input_.get()), crop_rect);
}
BlurPaintFilter::~BlurPaintFilter() = default;
size_t BlurPaintFilter::SerializedSize() const {
base::CheckedNumeric<size_t> total_size =
BaseSerializedSize() + PaintOpWriter::SerializedSize(sigma_x_) +
PaintOpWriter::SerializedSize(sigma_y_) +
PaintOpWriter::SerializedSize(tile_mode_);
total_size += PaintOpWriter::SerializedSize(input_.get());
return total_size.ValueOrDefault(0u);
}
sk_sp<PaintFilter> BlurPaintFilter::SnapshotWithImagesInternal(
ImageProvider* image_provider) const {
return sk_make_sp<BlurPaintFilter>(sigma_x_, sigma_y_, tile_mode_,
Snapshot(input_, image_provider),
GetCropRect());
}
bool BlurPaintFilter::EqualsForTesting(const BlurPaintFilter& other) const {
return sigma_x_ == other.sigma_x_ && sigma_y_ == other.sigma_y_ &&
tile_mode_ == other.tile_mode_ &&
AreValuesEqualForTesting(input_, other.input_); // IN-TEST
}
DropShadowPaintFilter::DropShadowPaintFilter(SkScalar dx,
SkScalar dy,
SkScalar sigma_x,
SkScalar sigma_y,
SkColor4f color,
ShadowMode shadow_mode,
sk_sp<PaintFilter> input,
const CropRect* crop_rect)
: PaintFilter(kType, crop_rect, HasDiscardableImages(input)),
dx_(dx),
dy_(dy),
sigma_x_(sigma_x),
sigma_y_(sigma_y),
color_(color),
shadow_mode_(shadow_mode),
input_(std::move(input)) {
if (shadow_mode == ShadowMode::kDrawShadowOnly) {
// TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
cached_sk_filter_ = SkImageFilters::DropShadowOnly(
dx_, dy_, sigma_x_, sigma_y_, color_.toSkColor(),
GetSkFilter(input_.get()), crop_rect);
} else {
// TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
cached_sk_filter_ = SkImageFilters::DropShadow(
dx_, dy_, sigma_x_, sigma_y_, color_.toSkColor(),
GetSkFilter(input_.get()), crop_rect);
}
}
DropShadowPaintFilter::~DropShadowPaintFilter() = default;
size_t DropShadowPaintFilter::SerializedSize() const {
base::CheckedNumeric<size_t> total_size =
BaseSerializedSize() + PaintOpWriter::SerializedSize(dx_) +
PaintOpWriter::SerializedSize(dy_) +
PaintOpWriter::SerializedSize(sigma_x_) +
PaintOpWriter::SerializedSize(sigma_y_) +
PaintOpWriter::SerializedSize(color_) +
PaintOpWriter::SerializedSize(shadow_mode_);
total_size += PaintOpWriter::SerializedSize(input_.get());
return total_size.ValueOrDefault(0u);
}
sk_sp<PaintFilter> DropShadowPaintFilter::SnapshotWithImagesInternal(
ImageProvider* image_provider) const {
return sk_make_sp<DropShadowPaintFilter>(
dx_, dy_, sigma_x_, sigma_y_, color_, shadow_mode_,
Snapshot(input_, image_provider), GetCropRect());
}
bool DropShadowPaintFilter::EqualsForTesting(
const DropShadowPaintFilter& other) const {
return dx_ == other.dx_ && dy_ == other.dy_ && sigma_x_ == other.sigma_x_ &&
sigma_y_ == other.sigma_y_ && color_ == other.color_ &&
shadow_mode_ == other.shadow_mode_ &&
AreValuesEqualForTesting(input_, other.input_); // IN-TEST
}
MagnifierPaintFilter::MagnifierPaintFilter(const SkRect& src_rect,
SkScalar inset,
sk_sp<PaintFilter> input,
const CropRect* crop_rect)
: PaintFilter(kType, crop_rect, HasDiscardableImages(input)),
src_rect_(src_rect),
inset_(inset),
input_(std::move(input)) {
cached_sk_filter_ = SkImageFilters::Magnifier(
src_rect_, inset_, GetSkFilter(input_.get()), crop_rect);
}
MagnifierPaintFilter::~MagnifierPaintFilter() = default;
size_t MagnifierPaintFilter::SerializedSize() const {
base::CheckedNumeric<size_t> total_size =
BaseSerializedSize() + PaintOpWriter::SerializedSize(src_rect_) +
PaintOpWriter::SerializedSize(inset_);
total_size += PaintOpWriter::SerializedSize(input_.get());
return total_size.ValueOrDefault(0u);
}
sk_sp<PaintFilter> MagnifierPaintFilter::SnapshotWithImagesInternal(
ImageProvider* image_provider) const {
return sk_make_sp<MagnifierPaintFilter>(
src_rect_, inset_, Snapshot(input_, image_provider), GetCropRect());
}
bool MagnifierPaintFilter::EqualsForTesting(
const MagnifierPaintFilter& other) const {
return src_rect_ == other.src_rect_ && inset_ == other.inset_ &&
AreValuesEqualForTesting(input_, other.input_); // IN-TEST
}
ComposePaintFilter::ComposePaintFilter(sk_sp<PaintFilter> outer,
sk_sp<PaintFilter> inner)
: PaintFilter(Type::kCompose,
nullptr,
HasDiscardableImages(outer) || HasDiscardableImages(inner)),
outer_(std::move(outer)),
inner_(std::move(inner)) {
cached_sk_filter_ = SkImageFilters::Compose(GetSkFilter(outer_.get()),
GetSkFilter(inner_.get()));
}
ComposePaintFilter::~ComposePaintFilter() = default;
size_t ComposePaintFilter::SerializedSize() const {
base::CheckedNumeric<size_t> total_size = BaseSerializedSize();
total_size += PaintOpWriter::SerializedSize(outer_.get());
total_size += PaintOpWriter::SerializedSize(inner_.get());
return total_size.ValueOrDefault(0u);
}
sk_sp<PaintFilter> ComposePaintFilter::SnapshotWithImagesInternal(
ImageProvider* image_provider) const {
return sk_make_sp<ComposePaintFilter>(Snapshot(outer_, image_provider),
Snapshot(inner_, image_provider));
}
bool ComposePaintFilter::EqualsForTesting(
const ComposePaintFilter& other) const {
return AreValuesEqualForTesting(outer_, other.outer_) && // IN-TEST
AreValuesEqualForTesting(inner_, other.inner_); // IN-TEST
}
AlphaThresholdPaintFilter::AlphaThresholdPaintFilter(const SkRegion& region,
SkScalar inner_min,
SkScalar outer_max,
sk_sp<PaintFilter> input,
const CropRect* crop_rect)
: PaintFilter(kType, crop_rect, HasDiscardableImages(input)),
region_(region),
inner_min_(inner_min),
outer_max_(outer_max),
input_(std::move(input)) {
cached_sk_filter_ = SkImageFilters::AlphaThreshold(
region_, inner_min_, outer_max_, GetSkFilter(input_.get()), crop_rect);
}
AlphaThresholdPaintFilter::~AlphaThresholdPaintFilter() = default;
size_t AlphaThresholdPaintFilter::SerializedSize() const {
size_t region_size = region_.writeToMemory(nullptr);
base::CheckedNumeric<size_t> total_size;
total_size = BaseSerializedSize() +
PaintOpWriter::SerializedSizeOfBytes(region_size) +
PaintOpWriter::SerializedSize(inner_min_) +
PaintOpWriter::SerializedSize(outer_max_);
total_size += PaintOpWriter::SerializedSize(input_.get());
return total_size.ValueOrDefault(0u);
}
sk_sp<PaintFilter> AlphaThresholdPaintFilter::SnapshotWithImagesInternal(
ImageProvider* image_provider) const {
return sk_make_sp<AlphaThresholdPaintFilter>(region_, inner_min_, outer_max_,
Snapshot(input_, image_provider),
GetCropRect());
}
bool AlphaThresholdPaintFilter::EqualsForTesting(
const AlphaThresholdPaintFilter& other) const {
return region_ == other.region_ && inner_min_ == other.inner_min_ &&
outer_max_ == other.outer_max_ &&
AreValuesEqualForTesting(input_, other.input_); // IN-TEST
}
XfermodePaintFilter::XfermodePaintFilter(SkBlendMode blend_mode,
sk_sp<PaintFilter> background,
sk_sp<PaintFilter> foreground,
const CropRect* crop_rect)
: PaintFilter(
kType,
crop_rect,
HasDiscardableImages(background) || HasDiscardableImages(foreground)),
blend_mode_(blend_mode),
background_(std::move(background)),
foreground_(std::move(foreground)) {
cached_sk_filter_ =
SkImageFilters::Blend(blend_mode_, GetSkFilter(background_.get()),
GetSkFilter(foreground_.get()), crop_rect);
}
XfermodePaintFilter::~XfermodePaintFilter() = default;
size_t XfermodePaintFilter::SerializedSize() const {
base::CheckedNumeric<size_t> total_size =
BaseSerializedSize() + PaintOpWriter::SerializedSize(blend_mode_);
total_size += PaintOpWriter::SerializedSize(background_.get());
total_size += PaintOpWriter::SerializedSize(foreground_.get());
return total_size.ValueOrDefault(0u);
}
sk_sp<PaintFilter> XfermodePaintFilter::SnapshotWithImagesInternal(
ImageProvider* image_provider) const {
return sk_make_sp<XfermodePaintFilter>(
blend_mode_, Snapshot(background_, image_provider),
Snapshot(foreground_, image_provider), GetCropRect());
}
bool XfermodePaintFilter::EqualsForTesting(
const XfermodePaintFilter& other) const {
return blend_mode_ == other.blend_mode_ &&
AreValuesEqualForTesting(background_, other.background_) && // IN-TEST
AreValuesEqualForTesting(foreground_, other.foreground_); // IN-TEST
}
ArithmeticPaintFilter::ArithmeticPaintFilter(float k1,
float k2,
float k3,
float k4,
bool enforce_pm_color,
sk_sp<PaintFilter> background,
sk_sp<PaintFilter> foreground,
const CropRect* crop_rect)
: PaintFilter(
kType,
crop_rect,
HasDiscardableImages(background) || HasDiscardableImages(foreground)),
k1_(k1),
k2_(k2),
k3_(k3),
k4_(k4),
enforce_pm_color_(enforce_pm_color),
background_(std::move(background)),
foreground_(std::move(foreground)) {
cached_sk_filter_ = SkImageFilters::Arithmetic(
k1_, k2_, k3_, k4_, enforce_pm_color_, GetSkFilter(background_.get()),
GetSkFilter(foreground_.get()), crop_rect);
}
ArithmeticPaintFilter::~ArithmeticPaintFilter() = default;
size_t ArithmeticPaintFilter::SerializedSize() const {
base::CheckedNumeric<size_t> total_size =
BaseSerializedSize() + PaintOpWriter::SerializedSize(k1_) +
PaintOpWriter::SerializedSize(k2_) + PaintOpWriter::SerializedSize(k3_) +
PaintOpWriter::SerializedSize(k4_) +
PaintOpWriter::SerializedSize(enforce_pm_color_);
total_size += PaintOpWriter::SerializedSize(background_.get());
total_size += PaintOpWriter::SerializedSize(foreground_.get());
return total_size.ValueOrDefault(0u);
}
sk_sp<PaintFilter> ArithmeticPaintFilter::SnapshotWithImagesInternal(
ImageProvider* image_provider) const {
return sk_make_sp<ArithmeticPaintFilter>(
k1_, k2_, k3_, k4_, enforce_pm_color_,
Snapshot(background_, image_provider),
Snapshot(foreground_, image_provider), GetCropRect());
}
bool ArithmeticPaintFilter::EqualsForTesting(
const ArithmeticPaintFilter& other) const {
return k1_ == other.k1_ && k2_ == other.k2_ && k3_ == other.k3_ &&
k4_ == other.k4_ && enforce_pm_color_ == other.enforce_pm_color_ &&
AreValuesEqualForTesting(background_, other.background_) && // IN-TEST
AreValuesEqualForTesting(foreground_, other.foreground_); // IN-TEST
}
MatrixConvolutionPaintFilter::MatrixConvolutionPaintFilter(
const SkISize& kernel_size,
const SkScalar* kernel,
SkScalar gain,
SkScalar bias,
const SkIPoint& kernel_offset,
SkTileMode tile_mode,
bool convolve_alpha,
sk_sp<PaintFilter> input,
const CropRect* crop_rect)
: PaintFilter(kType, crop_rect, HasDiscardableImages(input)),
kernel_size_(kernel_size),
gain_(gain),
bias_(bias),
kernel_offset_(kernel_offset),
tile_mode_(tile_mode),
convolve_alpha_(convolve_alpha),
input_(std::move(input)) {
DCHECK(kernel_size_.width() >= 0 && kernel_size_.height() >= 0);
auto len = static_cast<size_t>(kernel_size_.width()) *
static_cast<size_t>(kernel_size_.height());
kernel_->reserve(len);
for (size_t i = 0; i < len; ++i)
kernel_->push_back(kernel[i]);
cached_sk_filter_ = SkImageFilters::MatrixConvolution(
kernel_size_, kernel, gain_, bias_, kernel_offset_, tile_mode_,
convolve_alpha_, GetSkFilter(input_.get()), crop_rect);
}
MatrixConvolutionPaintFilter::~MatrixConvolutionPaintFilter() = default;
size_t MatrixConvolutionPaintFilter::SerializedSize() const {
base::CheckedNumeric<size_t> total_size =
BaseSerializedSize() + PaintOpWriter::SerializedSize(kernel_size_) +
PaintOpWriter::SerializedSize<size_t>() +
PaintOpWriter::SerializedSizeOfElements(kernel_->data(),
kernel_->size()) +
PaintOpWriter::SerializedSize(gain_) +
PaintOpWriter::SerializedSize(bias_) +
PaintOpWriter::SerializedSize(kernel_offset_) +
PaintOpWriter::SerializedSize(tile_mode_) +
PaintOpWriter::SerializedSize(convolve_alpha_);
total_size += PaintOpWriter::SerializedSize(input_.get());
return total_size.ValueOrDefault(0u);
}
sk_sp<PaintFilter> MatrixConvolutionPaintFilter::SnapshotWithImagesInternal(
ImageProvider* image_provider) const {
return sk_make_sp<MatrixConvolutionPaintFilter>(
kernel_size_, &kernel_[0], gain_, bias_, kernel_offset_, tile_mode_,
convolve_alpha_, Snapshot(input_, image_provider), GetCropRect());
}
bool MatrixConvolutionPaintFilter::EqualsForTesting(
const MatrixConvolutionPaintFilter& other) const {
return kernel_size_ == other.kernel_size_ &&
base::ranges::equal(kernel_.container(), other.kernel_.container()) &&
gain_ == other.gain_ && bias_ == other.bias_ &&
kernel_offset_ == other.kernel_offset_ &&
tile_mode_ == other.tile_mode_ &&
convolve_alpha_ == other.convolve_alpha_ &&
AreValuesEqualForTesting(input_, other.input_); // IN-TEST
}
DisplacementMapEffectPaintFilter::DisplacementMapEffectPaintFilter(
SkColorChannel channel_x,
SkColorChannel channel_y,
SkScalar scale,
sk_sp<PaintFilter> displacement,
sk_sp<PaintFilter> color,
const CropRect* crop_rect)
: PaintFilter(
kType,
crop_rect,
HasDiscardableImages(displacement) || HasDiscardableImages(color)),
channel_x_(channel_x),
channel_y_(channel_y),
scale_(scale),
displacement_(std::move(displacement)),
color_(std::move(color)) {
cached_sk_filter_ = SkImageFilters::DisplacementMap(
channel_x_, channel_y_, scale_, GetSkFilter(displacement_.get()),
GetSkFilter(color_.get()), crop_rect);
}
DisplacementMapEffectPaintFilter::~DisplacementMapEffectPaintFilter() = default;
size_t DisplacementMapEffectPaintFilter::SerializedSize() const {
base::CheckedNumeric<size_t> total_size =
BaseSerializedSize() + PaintOpWriter::SerializedSize(channel_x_) +
PaintOpWriter::SerializedSize(channel_y_) +
PaintOpWriter::SerializedSize(scale_);
total_size += PaintOpWriter::SerializedSize(displacement_.get());
total_size += PaintOpWriter::SerializedSize(color_.get());
return total_size.ValueOrDefault(0u);
}
sk_sp<PaintFilter> DisplacementMapEffectPaintFilter::SnapshotWithImagesInternal(
ImageProvider* image_provider) const {
return sk_make_sp<DisplacementMapEffectPaintFilter>(
channel_x_, channel_y_, scale_, Snapshot(displacement_, image_provider),
Snapshot(color_, image_provider), GetCropRect());
}
bool DisplacementMapEffectPaintFilter::EqualsForTesting(
const DisplacementMapEffectPaintFilter& other) const {
return channel_x_ == other.channel_x_ && channel_y_ == other.channel_y_ &&
scale_ == other.scale_ &&
AreValuesEqualForTesting(displacement_, // IN-TEST
other.displacement_) &&
AreValuesEqualForTesting(color_, other.color_); // IN-TEST
}
ImagePaintFilter::ImagePaintFilter(PaintImage image,
const SkRect& src_rect,
const SkRect& dst_rect,
PaintFlags::FilterQuality filter_quality)
: PaintFilter(kType, nullptr, !image.IsTextureBacked()),
image_(std::move(image)),
src_rect_(src_rect),
dst_rect_(dst_rect),
filter_quality_(filter_quality) {
SkSamplingOptions sampling(
PaintFlags::FilterQualityToSkSamplingOptions(filter_quality));
cached_sk_filter_ = SkImageFilters::Image(image_.GetSkImage(), src_rect_,
dst_rect_, sampling);
}
ImagePaintFilter::~ImagePaintFilter() = default;
size_t ImagePaintFilter::SerializedSize() const {
base::CheckedNumeric<size_t> total_size =
BaseSerializedSize() + PaintOpWriter::SerializedSize(src_rect_) +
PaintOpWriter::SerializedSize(dst_rect_) +
PaintOpWriter::SerializedSize(filter_quality_);
total_size += PaintOpWriter::SerializedSize(image_);
return total_size.ValueOrDefault(0u);
}
sk_sp<PaintFilter> ImagePaintFilter::SnapshotWithImagesInternal(
ImageProvider* image_provider) const {
DrawImage draw_image(image_, false,
SkIRect::MakeWH(image_.width(), image_.height()),
filter_quality_, SkM44());
auto scoped_result = image_provider->GetRasterContent(draw_image);
if (!scoped_result)
return nullptr;
auto decoded_sk_image = sk_ref_sp<SkImage>(
const_cast<SkImage*>(scoped_result.decoded_image().image().get()));
PaintImage decoded_paint_image =
PaintImageBuilder::WithDefault()
.set_id(image_.stable_id())
.set_texture_image(decoded_sk_image, PaintImage::GetNextContentId())
.TakePaintImage();
return sk_make_sp<ImagePaintFilter>(std::move(decoded_paint_image), src_rect_,
dst_rect_, filter_quality_);
}
bool ImagePaintFilter::EqualsForTesting(const ImagePaintFilter& other) const {
return !!image_ == !!other.image_ && src_rect_ == other.src_rect_ &&
dst_rect_ == other.dst_rect_ &&
filter_quality_ == other.filter_quality_;
}
RecordPaintFilter::RecordPaintFilter(PaintRecord record,
const SkRect& record_bounds,
const gfx::SizeF& raster_scale,
ScalingBehavior scaling_behavior)
: RecordPaintFilter(std::move(record),
record_bounds,
raster_scale,
scaling_behavior,
nullptr) {}
RecordPaintFilter::RecordPaintFilter(PaintRecord record,
const SkRect& record_bounds,
const gfx::SizeF& raster_scale,
ScalingBehavior scaling_behavior,
ImageProvider* image_provider)
: PaintFilter(kType, nullptr, record.HasDiscardableImages()),
record_(std::move(record)),
record_bounds_(record_bounds),
raster_scale_(raster_scale),
scaling_behavior_(scaling_behavior) {
DCHECK(raster_scale_.width() > 0.f && raster_scale_.height() > 0.f);
DCHECK(scaling_behavior == ScalingBehavior::kFixedScale ||
(raster_scale_.width() == 1.f && raster_scale_.height() == 1.f));
sk_sp<SkPicture> picture =
record_.ToSkPicture(record_bounds_, image_provider);
if (scaling_behavior == ScalingBehavior::kRasterAtScale ||
record_bounds_.isEmpty()) {
cached_sk_filter_ = SkImageFilters::Picture(std::move(picture));
} else {
DCHECK(scaling_behavior == ScalingBehavior::kFixedScale);
// Convert the record to an image at the scaled resolution, but draw it in
// the filter DAG at the original record bounds.
int width = SkScalarCeilToInt(record_bounds.width());
int height = SkScalarCeilToInt(record_bounds.height());
SkMatrix originAdjust =
SkMatrix::Translate(-record_bounds.fLeft, -record_bounds.fTop);
auto image = SkImages::DeferredFromPicture(
std::move(picture), SkISize::Make(width, height), &originAdjust,
nullptr, SkImages::BitDepth::kU8, SkColorSpace::MakeSRGB());
// Must account for the raster scale when drawing the picture image,
SkRect src = SkRect::MakeWH(record_bounds.width(), record_bounds.height());
SkScalar inv_x = 1.f / raster_scale_.width();
SkScalar inv_y = 1.f / raster_scale_.height();
SkRect dst = {inv_x * record_bounds.fLeft, inv_y * record_bounds.fTop,
inv_x * record_bounds.fRight, inv_y * record_bounds.fBottom};
// Use Mitchell cubic filter, matching historic
// PaintFlags::FilterQuality::kHigh
SkSamplingOptions sampling(SkCubicResampler::Mitchell());
cached_sk_filter_ =
SkImageFilters::Image(std::move(image), src, dst, sampling);
}
}
RecordPaintFilter::~RecordPaintFilter() = default;
sk_sp<RecordPaintFilter> RecordPaintFilter::CreateScaledPaintRecord(
const SkMatrix& ctm,
int max_texture_size) const {
// If this is already fixed scale, then this is already good to go, and if
// the bounds are empty the filter produces no output so keep it as-is.
if (scaling_behavior_ == ScalingBehavior::kFixedScale ||
record_bounds_.isEmpty()) {
return sk_ref_sp<RecordPaintFilter>(this);
}
// For creating a deserialized RecordPaintFilter, extract the scale factor at
// which it would have been rasterized at for the given ctm. This is modeled
// after PaintShader::CreateScaledPaintRecord.
SkRect scaled_record_bounds =
PaintRecord::GetFixedScaleBounds(ctm, record_bounds_, max_texture_size);
gfx::SizeF raster_scale = {
scaled_record_bounds.width() / record_bounds_.width(),
scaled_record_bounds.height() / record_bounds_.height()};
if (raster_scale.IsEmpty())
return nullptr;
return sk_make_sp<RecordPaintFilter>(record_, scaled_record_bounds,
raster_scale,
ScalingBehavior::kFixedScale);
}
size_t RecordPaintFilter::SerializedSize() const {
base::CheckedNumeric<size_t> total_size =
BaseSerializedSize() + PaintOpWriter::SerializedSize(record_bounds_) +
PaintOpWriter::SerializedSize(raster_scale_) +
PaintOpWriter::SerializedSize(scaling_behavior_);
total_size += PaintOpWriter::SerializedSize(record_);
return total_size.ValueOrDefault(0u);
}
sk_sp<PaintFilter> RecordPaintFilter::SnapshotWithImagesInternal(
ImageProvider* image_provider) const {
return sk_sp<RecordPaintFilter>(
new RecordPaintFilter(record_, record_bounds_, raster_scale_,
scaling_behavior_, image_provider));
}
bool RecordPaintFilter::EqualsForTesting(const RecordPaintFilter& other) const {
return record_.EqualsForTesting(other.record_) && // IN-TEST
scaling_behavior_ == other.scaling_behavior_ &&
raster_scale_ == other.raster_scale_ &&
record_bounds_ == other.record_bounds_;
}
MergePaintFilter::MergePaintFilter(const sk_sp<PaintFilter>* const filters,
int count,
const CropRect* crop_rect)
: MergePaintFilter(filters, count, crop_rect, nullptr) {}
MergePaintFilter::MergePaintFilter(const sk_sp<PaintFilter>* const filters,
int count,
const CropRect* crop_rect,
ImageProvider* image_provider)
: PaintFilter(kType, crop_rect, HasDiscardableImages(filters, count)) {
std::vector<sk_sp<SkImageFilter>> sk_filters;
sk_filters.reserve(count);
for (int i = 0; i < count; ++i) {
auto filter =
image_provider ? Snapshot(filters[i], image_provider) : filters[i];
inputs_->push_back(std::move(filter));
sk_filters.push_back(GetSkFilter(inputs_->back().get()));
}
cached_sk_filter_ = SkImageFilters::Merge(
static_cast<sk_sp<SkImageFilter>*>(sk_filters.data()), count, crop_rect);
}
MergePaintFilter::~MergePaintFilter() = default;
size_t MergePaintFilter::SerializedSize() const {
base::CheckedNumeric<size_t> total_size = BaseSerializedSize();
total_size += PaintOpWriter::SerializedSize(input_count());
for (size_t i = 0; i < input_count(); ++i) {
total_size += PaintOpWriter::SerializedSize(input_at(i));
}
return total_size.ValueOrDefault(0u);
}
sk_sp<PaintFilter> MergePaintFilter::SnapshotWithImagesInternal(
ImageProvider* image_provider) const {
return sk_sp<MergePaintFilter>(new MergePaintFilter(
&inputs_[0], inputs_->size(), GetCropRect(), image_provider));
}
bool MergePaintFilter::EqualsForTesting(const MergePaintFilter& other) const {
return base::ranges::equal(
inputs_, other.inputs_, [](const auto& a, const auto& b) {
return AreValuesEqualForTesting(a, b); // IN-TEST
});
}
MorphologyPaintFilter::MorphologyPaintFilter(MorphType morph_type,
float radius_x,
float radius_y,
sk_sp<PaintFilter> input,
const CropRect* crop_rect)
: PaintFilter(kType, crop_rect, HasDiscardableImages(input)),
morph_type_(morph_type),
radius_x_(radius_x),
radius_y_(radius_y),
input_(std::move(input)) {
switch (morph_type_) {
case MorphType::kDilate:
cached_sk_filter_ = SkImageFilters::Dilate(
radius_x_, radius_y_, GetSkFilter(input_.get()), crop_rect);
break;
case MorphType::kErode:
cached_sk_filter_ = SkImageFilters::Erode(
radius_x_, radius_y_, GetSkFilter(input_.get()), crop_rect);
break;
}
}
MorphologyPaintFilter::~MorphologyPaintFilter() = default;
size_t MorphologyPaintFilter::SerializedSize() const {
base::CheckedNumeric<size_t> total_size =
BaseSerializedSize() + PaintOpWriter::SerializedSize(morph_type_) +
PaintOpWriter::SerializedSize(radius_x_) +
PaintOpWriter::SerializedSize(radius_y_);
total_size += PaintOpWriter::SerializedSize(input_.get());
return total_size.ValueOrDefault(0u);
}
sk_sp<PaintFilter> MorphologyPaintFilter::SnapshotWithImagesInternal(
ImageProvider* image_provider) const {
return sk_make_sp<MorphologyPaintFilter>(morph_type_, radius_x_, radius_y_,
Snapshot(input_, image_provider),
GetCropRect());
}
bool MorphologyPaintFilter::EqualsForTesting(
const MorphologyPaintFilter& other) const {
return morph_type_ == other.morph_type_ && radius_x_ == other.radius_x_ &&
radius_y_ == other.radius_y_ &&
AreValuesEqualForTesting(input_, other.input_); // IN-TEST
}
OffsetPaintFilter::OffsetPaintFilter(SkScalar dx,
SkScalar dy,
sk_sp<PaintFilter> input,
const CropRect* crop_rect)
: PaintFilter(kType, crop_rect, HasDiscardableImages(input)),
dx_(dx),
dy_(dy),
input_(std::move(input)) {
cached_sk_filter_ =
SkImageFilters::Offset(dx_, dy_, GetSkFilter(input_.get()), crop_rect);
}
OffsetPaintFilter::~OffsetPaintFilter() = default;
size_t OffsetPaintFilter::SerializedSize() const {
base::CheckedNumeric<size_t> total_size = BaseSerializedSize() +
PaintOpWriter::SerializedSize(dx_) +
PaintOpWriter::SerializedSize(dy_);
total_size += PaintOpWriter::SerializedSize(input_.get());
return total_size.ValueOrDefault(0u);
}
sk_sp<PaintFilter> OffsetPaintFilter::SnapshotWithImagesInternal(
ImageProvider* image_provider) const {
return sk_make_sp<OffsetPaintFilter>(
dx_, dy_, Snapshot(input_, image_provider), GetCropRect());
}
bool OffsetPaintFilter::EqualsForTesting(const OffsetPaintFilter& other) const {
return dx_ == other.dx_ && dy_ == other.dy_ &&
AreValuesEqualForTesting(input_, other.input_); // IN-TEST
}
TilePaintFilter::TilePaintFilter(const SkRect& src,
const SkRect& dst,
sk_sp<PaintFilter> input)
: PaintFilter(kType, nullptr, HasDiscardableImages(input)),
src_(src),
dst_(dst),
input_(std::move(input)) {
cached_sk_filter_ =
SkImageFilters::Tile(src_, dst_, GetSkFilter(input_.get()));
}
TilePaintFilter::~TilePaintFilter() = default;
size_t TilePaintFilter::SerializedSize() const {
base::CheckedNumeric<size_t> total_size =
BaseSerializedSize() + PaintOpWriter::SerializedSize(src_) +
PaintOpWriter::SerializedSize(dst_);
total_size += PaintOpWriter::SerializedSize(input_.get());
return total_size.ValueOrDefault(0u);
}
sk_sp<PaintFilter> TilePaintFilter::SnapshotWithImagesInternal(
ImageProvider* image_provider) const {
return sk_make_sp<TilePaintFilter>(src_, dst_,
Snapshot(input_, image_provider));
}
bool TilePaintFilter::EqualsForTesting(const TilePaintFilter& other) const {
return src_ == other.src_ && dst_ == other.dst_ &&
AreValuesEqualForTesting(input_, other.input_); // IN-TEST
}
TurbulencePaintFilter::TurbulencePaintFilter(TurbulenceType turbulence_type,
SkScalar base_frequency_x,
SkScalar base_frequency_y,
int num_octaves,
SkScalar seed,
const SkISize* tile_size,
const CropRect* crop_rect)
: PaintFilter(kType, crop_rect, kHasNoDiscardableImages),
turbulence_type_(turbulence_type),
base_frequency_x_(base_frequency_x),
base_frequency_y_(base_frequency_y),
num_octaves_(num_octaves),
seed_(seed),
tile_size_(tile_size ? *tile_size : SkISize::MakeEmpty()) {
sk_sp<SkShader> shader;
switch (turbulence_type_) {
case TurbulenceType::kTurbulence:
shader = SkShaders::MakeTurbulence(base_frequency_x_, base_frequency_y_,
num_octaves_, seed_, &tile_size_);
break;
case TurbulenceType::kFractalNoise:
shader = SkShaders::MakeFractalNoise(base_frequency_x_, base_frequency_y_,
num_octaves_, seed_, &tile_size_);
break;
}
cached_sk_filter_ = SkImageFilters::Shader(std::move(shader), crop_rect);
}
TurbulencePaintFilter::~TurbulencePaintFilter() = default;
size_t TurbulencePaintFilter::SerializedSize() const {
return BaseSerializedSize() +
PaintOpWriter::SerializedSize(turbulence_type_) +
PaintOpWriter::SerializedSize(base_frequency_x_) +
PaintOpWriter::SerializedSize(base_frequency_y_) +
PaintOpWriter::SerializedSize(num_octaves_) +
PaintOpWriter::SerializedSize(seed_) +
PaintOpWriter::SerializedSize(tile_size_);
}
sk_sp<PaintFilter> TurbulencePaintFilter::SnapshotWithImagesInternal(
ImageProvider* image_provider) const {
return sk_make_sp<TurbulencePaintFilter>(turbulence_type_, base_frequency_x_,
base_frequency_y_, num_octaves_,
seed_, &tile_size_, GetCropRect());
}
bool TurbulencePaintFilter::EqualsForTesting(
const TurbulencePaintFilter& other) const {
return turbulence_type_ == other.turbulence_type_ &&
base_frequency_x_ == other.base_frequency_x_ &&
base_frequency_y_ == other.base_frequency_y_ &&
num_octaves_ == other.num_octaves_ && seed_ == other.seed_ &&
tile_size_ == other.tile_size_;
}
ShaderPaintFilter::ShaderPaintFilter(sk_sp<PaintShader> shader,
float alpha,
PaintFlags::FilterQuality filter_quality,
SkImageFilters::Dither dither,
const CropRect* crop_rect)
: PaintFilter(kType, crop_rect, shader->has_discardable_images()),
shader_(std::move(shader)),
alpha_(alpha),
filter_quality_(filter_quality),
dither_(dither) {
sk_sp<SkShader> sk_shader = shader_->GetSkShader(filter_quality_);
// Combine the alpha multiply into the SkShader if it's not opaque
if (alpha < 1.0f) {
// The blend effectively produces (shader * alpha), the rgb of the secondary
// color are ignored.
SkColor4f color{1.0f, 1.0f, 1.0f, alpha};
// TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
sk_shader = SkShaders::Blend(SkBlendMode::kDstIn, std::move(sk_shader),
SkShaders::Color(color.toSkColor()));
}
cached_sk_filter_ =
SkImageFilters::Shader(std::move(sk_shader), dither, crop_rect);
}
ShaderPaintFilter::~ShaderPaintFilter() = default;
size_t ShaderPaintFilter::SerializedSize() const {
base::CheckedNumeric<size_t> total_size = BaseSerializedSize();
total_size += PaintShader::GetSerializedSize(shader_.get());
total_size += PaintOpWriter::SerializedSize(alpha_);
total_size +=
PaintOpWriter::SerializedSize(filter_quality_); // filter quality
total_size += PaintOpWriter::SerializedSize(dither_);
return total_size.ValueOrDefault(0u);
}
sk_sp<PaintFilter> ShaderPaintFilter::SnapshotWithImagesInternal(
ImageProvider* image_provider) const {
PaintFlags orig_flags;
orig_flags.setShader(shader_);
orig_flags.setAlphaf(alpha_);
orig_flags.setFilterQuality(filter_quality_);
orig_flags.setDither(dither_ == SkImageFilters::Dither::kYes);
ScopedRasterFlags raster_flags(&orig_flags, image_provider, SkMatrix::I(), 0,
1.0f);
const PaintFlags* snapshot = raster_flags.flags();
if (snapshot) {
// Ref the updated paint shader so that it can outlive ScopedRasterFlags
return sk_make_sp<ShaderPaintFilter>(
sk_ref_sp(snapshot->getShader()), snapshot->getAlphaf(),
snapshot->getFilterQuality(),
snapshot->isDither() ? Dither::kYes : Dither::kNo, GetCropRect());
} else {
// If decode failed, then just fallback to the solid color
return sk_make_sp<ShaderPaintFilter>(nullptr, alpha_, filter_quality_,
dither_, GetCropRect());
}
}
bool ShaderPaintFilter::EqualsForTesting(const ShaderPaintFilter& other) const {
DCHECK(shader_ && other.shader_);
return alpha_ == other.alpha_ && filter_quality_ == other.filter_quality_ &&
dither_ == other.dither_ &&
shader_->EqualsForTesting(*other.shader_); // IN-TEST
}
MatrixPaintFilter::MatrixPaintFilter(const SkMatrix& matrix,
PaintFlags::FilterQuality filter_quality,
sk_sp<PaintFilter> input)
: PaintFilter(Type::kMatrix, nullptr, HasDiscardableImages(input)),
matrix_(matrix),
filter_quality_(filter_quality),
input_(std::move(input)) {
cached_sk_filter_ = SkImageFilters::MatrixTransform(
matrix_, PaintFlags::FilterQualityToSkSamplingOptions(filter_quality_),
GetSkFilter(input_.get()));
}
MatrixPaintFilter::~MatrixPaintFilter() = default;
size_t MatrixPaintFilter::SerializedSize() const {
base::CheckedNumeric<size_t> total_size =
BaseSerializedSize() + PaintOpWriter::SerializedSize(matrix_) +
PaintOpWriter::SerializedSize(filter_quality_);
total_size += PaintOpWriter::SerializedSize(input_.get());
return total_size.ValueOrDefault(0u);
}
sk_sp<PaintFilter> MatrixPaintFilter::SnapshotWithImagesInternal(
ImageProvider* image_provider) const {
return sk_make_sp<MatrixPaintFilter>(matrix_, filter_quality_,
Snapshot(input_, image_provider));
}
bool MatrixPaintFilter::EqualsForTesting(const MatrixPaintFilter& other) const {
return matrix_ == other.matrix_ && filter_quality_ == other.filter_quality_ &&
AreValuesEqualForTesting(input_, other.input_); // IN-TEST
}
LightingDistantPaintFilter::LightingDistantPaintFilter(
LightingType lighting_type,
const SkPoint3& direction,
SkColor4f light_color,
SkScalar surface_scale,
SkScalar kconstant,
SkScalar shininess,
sk_sp<PaintFilter> input,
const CropRect* crop_rect)
: PaintFilter(kType, crop_rect, HasDiscardableImages(input)),
lighting_type_(lighting_type),
direction_(direction),
light_color_(light_color),
surface_scale_(surface_scale),
kconstant_(kconstant),
shininess_(shininess),
input_(std::move(input)) {
switch (lighting_type_) {
case LightingType::kDiffuse:
// TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
cached_sk_filter_ = SkImageFilters::DistantLitDiffuse(
direction_, light_color_.toSkColor(), surface_scale_, kconstant_,
GetSkFilter(input_.get()), crop_rect);
break;
case LightingType::kSpecular:
// TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
cached_sk_filter_ = SkImageFilters::DistantLitSpecular(
direction_, light_color_.toSkColor(), surface_scale_, kconstant_,
shininess_, GetSkFilter(input_.get()), crop_rect);
break;
}
}
LightingDistantPaintFilter::~LightingDistantPaintFilter() = default;
size_t LightingDistantPaintFilter::SerializedSize() const {
base::CheckedNumeric<size_t> total_size =
BaseSerializedSize() + PaintOpWriter::SerializedSize(lighting_type_) +
PaintOpWriter::SerializedSize(direction_) +
PaintOpWriter::SerializedSize(light_color_) +
PaintOpWriter::SerializedSize(surface_scale_) +
PaintOpWriter::SerializedSize(kconstant_) +
PaintOpWriter::SerializedSize(shininess_);
total_size += PaintOpWriter::SerializedSize(input_.get());
return total_size.ValueOrDefault(0u);
}
sk_sp<PaintFilter> LightingDistantPaintFilter::SnapshotWithImagesInternal(
ImageProvider* image_provider) const {
return sk_make_sp<LightingDistantPaintFilter>(
lighting_type_, direction_, light_color_, surface_scale_, kconstant_,
shininess_, Snapshot(input_, image_provider), GetCropRect());
}
bool LightingDistantPaintFilter::EqualsForTesting(
const LightingDistantPaintFilter& other) const {
return lighting_type_ == other.lighting_type_ &&
direction_ == other.direction_ && light_color_ == other.light_color_ &&
surface_scale_ == other.surface_scale_ &&
kconstant_ == other.kconstant_ && shininess_ == other.shininess_ &&
AreValuesEqualForTesting(input_, other.input_); // IN-TEST
}
LightingPointPaintFilter::LightingPointPaintFilter(LightingType lighting_type,
const SkPoint3& location,
SkColor4f light_color,
SkScalar surface_scale,
SkScalar kconstant,
SkScalar shininess,
sk_sp<PaintFilter> input,
const CropRect* crop_rect)
: PaintFilter(kType, crop_rect, HasDiscardableImages(input)),
lighting_type_(lighting_type),
location_(location),
light_color_(light_color),
surface_scale_(surface_scale),
kconstant_(kconstant),
shininess_(shininess),
input_(std::move(input)) {
switch (lighting_type_) {
case LightingType::kDiffuse:
// TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
cached_sk_filter_ = SkImageFilters::PointLitDiffuse(
location_, light_color_.toSkColor(), surface_scale_, kconstant_,
GetSkFilter(input_.get()), crop_rect);
break;
case LightingType::kSpecular:
// TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
cached_sk_filter_ = SkImageFilters::PointLitSpecular(
location_, light_color_.toSkColor(), surface_scale_, kconstant_,
shininess_, GetSkFilter(input_.get()), crop_rect);
break;
}
}
LightingPointPaintFilter::~LightingPointPaintFilter() = default;
size_t LightingPointPaintFilter::SerializedSize() const {
base::CheckedNumeric<size_t> total_size =
BaseSerializedSize() + PaintOpWriter::SerializedSize(lighting_type_) +
PaintOpWriter::SerializedSize(location_) +
PaintOpWriter::SerializedSize(light_color_) +
PaintOpWriter::SerializedSize(surface_scale_) +
PaintOpWriter::SerializedSize(kconstant_) +
PaintOpWriter::SerializedSize(shininess_);
total_size += PaintOpWriter::SerializedSize(input_.get());
return total_size.ValueOrDefault(0u);
}
sk_sp<PaintFilter> LightingPointPaintFilter::SnapshotWithImagesInternal(
ImageProvider* image_provider) const {
return sk_make_sp<LightingPointPaintFilter>(
lighting_type_, location_, light_color_, surface_scale_, kconstant_,
shininess_, Snapshot(input_, image_provider), GetCropRect());
}
bool LightingPointPaintFilter::EqualsForTesting(
const LightingPointPaintFilter& other) const {
return lighting_type_ == other.lighting_type_ &&
location_ == other.location_ && light_color_ == other.light_color_ &&
surface_scale_ == other.surface_scale_ &&
kconstant_ == other.kconstant_ && shininess_ == other.shininess_ &&
AreValuesEqualForTesting(input_, other.input_); // IN-TEST
}
LightingSpotPaintFilter::LightingSpotPaintFilter(LightingType lighting_type,
const SkPoint3& location,
const SkPoint3& target,
SkScalar specular_exponent,
SkScalar cutoff_angle,
SkColor4f light_color,
SkScalar surface_scale,
SkScalar kconstant,
SkScalar shininess,
sk_sp<PaintFilter> input,
const CropRect* crop_rect)
: PaintFilter(kType, crop_rect, HasDiscardableImages(input)),
lighting_type_(lighting_type),
location_(location),
target_(target),
specular_exponent_(specular_exponent),
cutoff_angle_(cutoff_angle),
light_color_(light_color),
surface_scale_(surface_scale),
kconstant_(kconstant),
shininess_(shininess),
input_(std::move(input)) {
switch (lighting_type_) {
case LightingType::kDiffuse:
// TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
cached_sk_filter_ = SkImageFilters::SpotLitDiffuse(
location_, target_, specular_exponent_, cutoff_angle_,
light_color_.toSkColor(), surface_scale_, kconstant_,
GetSkFilter(input_.get()), crop_rect);
break;
case LightingType::kSpecular:
// TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
cached_sk_filter_ = SkImageFilters::SpotLitSpecular(
location_, target_, specular_exponent_, cutoff_angle_,
light_color_.toSkColor(), surface_scale_, kconstant_, shininess_,
GetSkFilter(input_.get()), crop_rect);
break;
}
}
LightingSpotPaintFilter::~LightingSpotPaintFilter() = default;
size_t LightingSpotPaintFilter::SerializedSize() const {
base::CheckedNumeric<size_t> total_size =
BaseSerializedSize() + PaintOpWriter::SerializedSize(lighting_type_) +
PaintOpWriter::SerializedSize(location_) +
PaintOpWriter::SerializedSize(target_) +
PaintOpWriter::SerializedSize(specular_exponent_) +
PaintOpWriter::SerializedSize(cutoff_angle_) +
PaintOpWriter::SerializedSize(light_color_) +
PaintOpWriter::SerializedSize(surface_scale_) +
PaintOpWriter::SerializedSize(kconstant_) +
PaintOpWriter::SerializedSize(shininess_);
total_size += PaintOpWriter::SerializedSize(input_.get());
return total_size.ValueOrDefault(0u);
}
sk_sp<PaintFilter> LightingSpotPaintFilter::SnapshotWithImagesInternal(
ImageProvider* image_provider) const {
return sk_make_sp<LightingSpotPaintFilter>(
lighting_type_, location_, target_, specular_exponent_, cutoff_angle_,
light_color_, surface_scale_, kconstant_, shininess_,
Snapshot(input_, image_provider), GetCropRect());
}
bool LightingSpotPaintFilter::EqualsForTesting(
const LightingSpotPaintFilter& other) const {
return lighting_type_ == other.lighting_type_ &&
location_ == other.location_ && target_ == other.target_ &&
specular_exponent_ == other.specular_exponent_ &&
cutoff_angle_ == other.cutoff_angle_ &&
light_color_ == other.light_color_ &&
surface_scale_ == other.surface_scale_ &&
kconstant_ == other.kconstant_ && shininess_ == other.shininess_ &&
AreValuesEqualForTesting(input_, other.input_); // IN-TEST
}
} // namespace cc