blob: 83e7ca04fef567d0b75982dd3069d026113cc35d [file] [log] [blame]
// Copyright 2024 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/path_effect.h"
#include <vector>
#include "base/check_op.h"
#include "base/compiler_specific.h"
#include "base/notreached.h"
#include "base/numerics/checked_math.h"
#include "base/numerics/safe_conversions.h"
#include "cc/paint/paint_op_reader.h"
#include "cc/paint/paint_op_writer.h"
#include "third_party/abseil-cpp/absl/container/inlined_vector.h"
#include "third_party/skia/include/core/SkPathEffect.h"
#include "third_party/skia/include/effects/SkCornerPathEffect.h"
#include "third_party/skia/include/effects/SkDashPathEffect.h"
namespace cc {
namespace {
template <typename T>
bool AreEqualForTesting(const PathEffect& a, const PathEffect& b) {
return static_cast<const T&>(a).EqualsForTesting( // IN-TEST
static_cast<const T&>(b));
}
class DashPathEffect final : public PathEffect {
public:
explicit DashPathEffect(const float intervals[], int count, float phase)
: PathEffect(Type::kDash),
intervals_(intervals, UNSAFE_TODO(intervals + count)),
phase_(phase) {}
bool EqualsForTesting(const DashPathEffect& other) const {
return phase_ == other.phase_ && intervals_ == other.intervals_;
}
private:
size_t SerializedDataSize() const override {
return (base::CheckedNumeric<size_t>(
PaintOpWriter::SerializedSizeOfElements(intervals_.data(),
intervals_.size())) +
PaintOpWriter::SerializedSize(phase_))
.ValueOrDie();
}
void SerializeData(PaintOpWriter& writer) const override {
writer.Write(intervals_);
writer.Write(phase_);
}
sk_sp<SkPathEffect> GetSkPathEffect() const override {
return SkDashPathEffect::Make(intervals_, phase_);
}
size_t dash_interval_count() const override { return intervals_.size(); }
absl::InlinedVector<float, 2> intervals_;
float phase_;
};
class CornerPathEffect final : public PathEffect {
public:
explicit CornerPathEffect(float radius)
: PathEffect(Type::kCorner), radius_(radius) {}
bool EqualsForTesting(const CornerPathEffect& other) const {
return radius_ == other.radius_;
}
private:
size_t SerializedDataSize() const override {
return PaintOpWriter::SerializedSize(radius_);
}
void SerializeData(PaintOpWriter& writer) const override {
writer.Write(radius_);
}
sk_sp<SkPathEffect> GetSkPathEffect() const override {
return SkCornerPathEffect::Make(radius_);
}
float radius_;
};
} // namespace
PathEffect::PathEffect(Type type) : type_(type) {
DCHECK_NE(type, Type::kNull);
}
sk_sp<PathEffect> PathEffect::MakeDash(const float* intervals,
int count,
float phase) {
return sk_make_sp<DashPathEffect>(intervals, count, phase);
}
sk_sp<PathEffect> PathEffect::MakeCorner(float radius) {
return sk_make_sp<CornerPathEffect>(radius);
}
size_t PathEffect::dash_interval_count() const {
return 0;
}
bool PathEffect::EqualsForTesting(const PathEffect& other) const {
if (type_ != other.type_) {
return false;
}
switch (type_) {
case Type::kNull:
return true;
case Type::kDash:
return AreEqualForTesting<DashPathEffect>(*this, other);
case Type::kCorner:
return AreEqualForTesting<CornerPathEffect>(*this, other);
}
NOTREACHED();
}
sk_sp<PathEffect> PathEffect::Deserialize(PaintOpReader& reader, Type type) {
switch (type) {
case Type::kDash: {
std::vector<float> intervals;
float phase;
reader.Read(intervals);
reader.Read(&phase);
return reader.valid()
? MakeDash(intervals.data(),
base::checked_cast<int>(intervals.size()), phase)
: nullptr;
}
case Type::kCorner: {
float radius;
reader.Read(&radius);
return reader.valid() ? MakeCorner(radius) : nullptr;
}
default:
NOTREACHED();
}
}
} // namespace cc