blob: a6d2f02361df30bb01958ae912f22a122819ce8e [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_DISPLAY_LIST_DISPLAY_LIST_PATH_EFFECT_H_
#define FLUTTER_DISPLAY_LIST_DISPLAY_LIST_PATH_EFFECT_H_
#include <cstring>
#include <optional>
#include "flutter/display_list/display_list_attributes.h"
#include "flutter/display_list/types.h"
#include "flutter/fml/logging.h"
#include "include/core/SkScalar.h"
namespace flutter {
class DlDashPathEffect;
// The DisplayList PathEffect class. This class implements all of the
// facilities and adheres to the design goals of the |DlAttribute| base
// class.
// An enumerated type for the recognized PathEffect operations.
// In current Flutter we only use the DashPathEffect.
// And another PathEffect outside of the recognized types is needed
// then a |kUnknown| type that simply defers to an SkPathEffect is
// provided as a fallback.
enum class DlPathEffectType {
kDash,
kUnknown,
};
class DlPathEffect
: public DlAttribute<DlPathEffect, SkPathEffect, DlPathEffectType> {
public:
static std::shared_ptr<DlPathEffect> From(SkPathEffect* sk_path_effect);
static std::shared_ptr<DlPathEffect> From(
sk_sp<SkPathEffect> sk_path_effect) {
return From(sk_path_effect.get());
}
virtual const DlDashPathEffect* asDash() const { return nullptr; }
virtual std::optional<SkRect> effect_bounds(SkRect&) const = 0;
protected:
DlPathEffect() = default;
private:
FML_DISALLOW_COPY_ASSIGN_AND_MOVE(DlPathEffect);
};
/// The DashPathEffect which breaks a path up into dash segments, and it
/// only affects stroked paths.
/// intervals: array containing an even number of entries (>=2), with
/// the even indices specifying the length of "on" intervals, and the odd
/// indices specifying the length of "off" intervals. This array will be
/// copied in Make, and can be disposed of freely after.
/// count: number of elements in the intervals array.
/// phase: initial distance into the intervals at which to start the dashing
/// effect for the path.
///
/// For example: if intervals[] = {10, 20}, count = 2, and phase = 25,
/// this will set up a dashed path like so:
/// 5 pixels off
/// 10 pixels on
/// 20 pixels off
/// 10 pixels on
/// 20 pixels off
/// ...
/// A phase of -5, 25, 55, 85, etc. would all result in the same path,
/// because the sum of all the intervals is 30.
///
class DlDashPathEffect final : public DlPathEffect {
public:
static std::shared_ptr<DlPathEffect> Make(const SkScalar intervals[],
int count,
SkScalar phase);
DlPathEffectType type() const override { return DlPathEffectType::kDash; }
size_t size() const override {
return sizeof(*this) + sizeof(SkScalar) * count_;
}
std::shared_ptr<DlPathEffect> shared() const override {
return Make(intervals(), count_, phase_);
}
const DlDashPathEffect* asDash() const override { return this; }
sk_sp<SkPathEffect> skia_object() const override {
return SkDashPathEffect::Make(intervals(), count_, phase_);
}
const SkScalar* intervals() const {
return reinterpret_cast<const SkScalar*>(this + 1);
}
std::optional<SkRect> effect_bounds(SkRect& rect) const override;
protected:
bool equals_(DlPathEffect const& other) const override {
FML_DCHECK(other.type() == DlPathEffectType::kDash);
auto that = static_cast<DlDashPathEffect const*>(&other);
return count_ == that->count_ && phase_ == that->phase_ &&
memcmp(intervals(), that->intervals(), sizeof(SkScalar) * count_) ==
0;
}
private:
// DlDashPathEffect constructor assumes the caller has prealloced storage for
// the intervals. If the intervals is nullptr the intervals will
// uninitialized.
DlDashPathEffect(const SkScalar intervals[], int count, SkScalar phase)
: count_(count), phase_(phase) {
if (intervals != nullptr) {
SkScalar* intervals_ = reinterpret_cast<SkScalar*>(this + 1);
memcpy(intervals_, intervals, sizeof(SkScalar) * count);
}
}
DlDashPathEffect(const DlDashPathEffect* dash_effect)
: DlDashPathEffect(dash_effect->intervals(),
dash_effect->count_,
dash_effect->phase_) {}
SkScalar* intervals_unsafe() { return reinterpret_cast<SkScalar*>(this + 1); }
int count_;
SkScalar phase_;
friend class DisplayListBuilder;
friend class DlPathEffect;
FML_DISALLOW_COPY_ASSIGN_AND_MOVE(DlDashPathEffect);
};
class DlUnknownPathEffect final : public DlPathEffect {
public:
DlUnknownPathEffect(sk_sp<SkPathEffect> effect)
: sk_path_effect_(std::move(effect)) {}
DlUnknownPathEffect(const DlUnknownPathEffect& effect)
: DlUnknownPathEffect(effect.sk_path_effect_) {}
DlUnknownPathEffect(const DlUnknownPathEffect* effect)
: DlUnknownPathEffect(effect->sk_path_effect_) {}
DlPathEffectType type() const override { return DlPathEffectType::kUnknown; }
size_t size() const override { return sizeof(*this); }
std::shared_ptr<DlPathEffect> shared() const override {
return std::make_shared<DlUnknownPathEffect>(this);
}
sk_sp<SkPathEffect> skia_object() const override { return sk_path_effect_; }
virtual ~DlUnknownPathEffect() = default;
std::optional<SkRect> effect_bounds(SkRect& rect) const override;
protected:
bool equals_(const DlPathEffect& other) const override {
FML_DCHECK(other.type() == DlPathEffectType::kUnknown);
auto that = static_cast<DlUnknownPathEffect const*>(&other);
return sk_path_effect_ == that->sk_path_effect_;
}
private:
sk_sp<SkPathEffect> sk_path_effect_;
};
} // namespace flutter
#endif // FLUTTER_DISPLAY_LIST_DISPLAY_LIST_PATH_EFFECT_H_