Flutter Engine
The Flutter Engine
RadialWipeEffect.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2019 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
10#include "include/core/SkRect.h"
24
25#include <algorithm>
26#include <cmath>
27#include <cstddef>
28#include <utility>
29#include <vector>
30
31class SkMatrix;
32
33namespace skjson {
34class ArrayValue;
35}
36namespace sksg {
37class InvalidationController;
38}
39
40namespace skottie {
41namespace internal {
42
43namespace {
44
45class RWipeRenderNode final : public sksg::CustomRenderNode {
46public:
47 explicit RWipeRenderNode(sk_sp<sksg::RenderNode> layer)
48 : INHERITED({std::move(layer)}) {}
49
50 SG_ATTRIBUTE(Completion, float , fCompletion)
51 SG_ATTRIBUTE(StartAngle, float , fStartAngle)
52 SG_ATTRIBUTE(WipeCenter, SkPoint, fWipeCenter)
53 SG_ATTRIBUTE(Wipe , float , fWipe )
54 SG_ATTRIBUTE(Feather , float , fFeather )
55
56protected:
57 const RenderNode* onNodeAt(const SkPoint&) const override { return nullptr; } // no hit-testing
58
59 SkRect onRevalidate(sksg::InvalidationController* ic, const SkMatrix& ctm) override {
60 SkASSERT(this->children().size() == 1ul);
61 const auto content_bounds = this->children()[0]->revalidate(ic, ctm);
62
63 if (fCompletion >= 100) {
64 return SkRect::MakeEmpty();
65 }
66
67 if (fCompletion <= 0) {
68 fMaskSigma = 0;
69 fMaskShader = nullptr;
70 } else {
71 fMaskSigma = std::max(fFeather, 0.0f) * kBlurSizeToSigma;
72
73 const auto t = fCompletion * 0.01f;
74
75 // Note: this could be simplified as a one-hard-stop gradient + local matrix
76 // (to apply rotation). Alas, local matrices are no longer supported in SkSG.
77 SkColor c0 = 0x00000000,
78 c1 = 0xffffffff;
79 auto sanitize_angle = [](float a) {
80 a = std::fmod(a, 360);
81 if (a < 0) {
82 a += 360;
83 }
84 return a;
85 };
86
87 auto a0 = sanitize_angle(fStartAngle - 90 + t * this->wipeAlignment()),
88 a1 = sanitize_angle(a0 + t * 360);
89 if (a0 > a1) {
90 std::swap(a0, a1);
91 std::swap(c0, c1);
92 }
93
94 const SkColor grad_colors[] = { c1, c0, c0, c1 };
95 const SkScalar grad_pos[] = { 0, 0, 1, 1 };
96
97 fMaskShader = SkGradientShader::MakeSweep(fWipeCenter.x(), fWipeCenter.y(),
98 grad_colors, grad_pos,
99 std::size(grad_colors),
101 a0, a1, 0, nullptr);
102
103 // Edge feather requires a real blur.
104 if (fMaskSigma > 0) {
105 // TODO: this feature is disabled ATM.
106 }
107 }
108
109 return content_bounds;
110 }
111
112 void onRender(SkCanvas* canvas, const RenderContext* ctx) const override {
113 if (fCompletion >= 100) {
114 // Fully masked out.
115 return;
116 }
117
118 const auto local_ctx = ScopedRenderContext(canvas, ctx)
119 .modulateMaskShader(fMaskShader, canvas->getTotalMatrix());
120 this->children()[0]->render(canvas, local_ctx);
121 }
122
123private:
124 float wipeAlignment() const {
125 switch (SkScalarRoundToInt(fWipe)) {
126 case 1: return 0.0f; // Clockwise
127 case 2: return -360.0f; // Counterclockwise
128 case 3: return -180.0f; // Both/center
129 default: break;
130 }
131 return 0.0f;
132 }
133
134 SkPoint fWipeCenter = { 0, 0 };
135 float fCompletion = 0,
136 fStartAngle = 0,
137 fWipe = 0,
138 fFeather = 0;
139
140 // Cached during revalidation.
141 sk_sp<SkShader> fMaskShader;
142 float fMaskSigma; // edge feather/blur
143
145};
146
147class RadialWipeAdapter final : public DiscardableAdapterBase<RadialWipeAdapter, RWipeRenderNode> {
148public:
149 RadialWipeAdapter(const skjson::ArrayValue& jprops,
151 const AnimationBuilder& abuilder)
152 : INHERITED(sk_make_sp<RWipeRenderNode>(std::move(layer))) {
153
154 enum : size_t {
155 kCompletion_Index = 0,
156 kStartAngle_Index = 1,
157 kWipeCenter_Index = 2,
158 kWipe_Index = 3,
159 kFeather_Index = 4,
160 };
161
162 EffectBinder(jprops, abuilder, this)
163 .bind(kCompletion_Index, fCompletion)
164 .bind(kStartAngle_Index, fStartAngle)
165 .bind(kWipeCenter_Index, fWipeCenter)
166 .bind( kWipe_Index, fWipe )
167 .bind( kFeather_Index, fFeather );
168 }
169
170private:
171 void onSync() override {
172 const auto& wiper = this->node();
173
174 wiper->setCompletion(fCompletion);
175 wiper->setStartAngle(fStartAngle);
176 wiper->setWipeCenter({fWipeCenter.x, fWipeCenter.y});
177 wiper->setWipe(fWipe);
178 wiper->setFeather(fFeather);
179 }
180
181 Vec2Value fWipeCenter = {0,0};
182 ScalarValue fCompletion = 0,
183 fStartAngle = 0,
184 fWipe = 0,
185 fFeather = 0;
186
187 using INHERITED = DiscardableAdapterBase<RadialWipeAdapter, RWipeRenderNode>;
188};
189
190} // namespace
191
192sk_sp<sksg::RenderNode> EffectBuilder::attachRadialWipeEffect(const skjson::ArrayValue& jprops,
193 sk_sp<sksg::RenderNode> layer) const {
194 return fBuilder->attachDiscardableAdapter<RadialWipeAdapter>(jprops,
195 std::move(layer),
196 *fBuilder);
197}
198
199} // namespace internal
200} // namespace skottie
#define SkASSERT(cond)
Definition: SkAssert.h:116
uint32_t SkColor
Definition: SkColor.h:37
#define INHERITED(method,...)
Definition: SkRecorder.cpp:128
sk_sp< T > sk_make_sp(Args &&... args)
Definition: SkRefCnt.h:371
void swap(sk_sp< T > &a, sk_sp< T > &b)
Definition: SkRefCnt.h:341
#define SG_ATTRIBUTE(attr_name, attr_type, attr_container)
Definition: SkSGNode.h:100
#define SkScalarRoundToInt(x)
Definition: SkScalar.h:37
SkMatrix getTotalMatrix() const
Definition: SkCanvas.cpp:1629
static sk_sp< SkShader > MakeSweep(SkScalar cx, SkScalar cy, const SkColor colors[], const SkScalar pos[], int count, SkTileMode mode, SkScalar startAngle, SkScalar endAngle, uint32_t flags, const SkMatrix *localMatrix)
void attachDiscardableAdapter(sk_sp< T > adapter) const
Definition: SkottiePriv.h:139
float SkScalar
Definition: extension.cpp:12
struct MyStruct a[10]
static float max(float r, float g, float b)
Definition: hsl.cpp:49
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
static constexpr float kBlurSizeToSigma
Definition: SkottiePriv.h:47
SkScalar ScalarValue
Definition: SkottieValue.h:22
SkV2 Vec2Value
Definition: SkottieValue.h:23
Definition: Skottie.h:32
Definition: ref_ptr.h:256
constexpr float y() const
Definition: SkPoint_impl.h:187
constexpr float x() const
Definition: SkPoint_impl.h:181
static constexpr SkRect MakeEmpty()
Definition: SkRect.h:595