| // 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_ |