Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
VenetianBlindsEffect.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
13#include "include/core/SkSize.h"
22
23#include <algorithm>
24#include <array>
25#include <cmath>
26#include <cstddef>
27#include <utility>
28
29namespace skjson {
30class ArrayValue;
31}
32
33namespace skottie {
34namespace internal {
35
36namespace {
37
38class VenetianBlindsAdapter final : public MaskShaderEffectBase {
39public:
42 const SkSize& layer_size,
43 const AnimationBuilder* abuilder) {
45 new VenetianBlindsAdapter(jprops, std::move(layer), layer_size, abuilder));
46 }
47
48private:
49 VenetianBlindsAdapter(const skjson::ArrayValue& jprops,
50 sk_sp<sksg::RenderNode> layer, const SkSize& ls,
51 const AnimationBuilder* abuilder)
52 : INHERITED(std::move(layer), ls) {
53 enum : size_t {
54 kCompletion_Index = 0,
55 kDirection_Index = 1,
56 kWidth_Index = 2,
57 kFeather_Index = 3,
58 };
59
60 EffectBinder(jprops, *abuilder, this)
61 .bind(kCompletion_Index, fCompletion)
62 .bind( kDirection_Index, fDirection )
63 .bind( kWidth_Index, fWidth )
64 .bind( kFeather_Index, fFeather );
65 }
66
67 MaskInfo onMakeMask() const override {
68 if (fCompletion >= 100) {
69 // The layer is fully disabled.
70 // TODO: fix layer controller visibility clash and pass a null shader instead.
71 return { SkShaders::Color(SK_ColorTRANSPARENT), false };
72 }
73
74 if (fCompletion <= 0) {
75 // The layer is fully visible (no mask).
76 return { nullptr, true };
77 }
78
79 static constexpr float kFeatherSigmaFactor = 3.0f,
80 kMinFeather = 0.5f; // for soft gradient edges
81
82 const auto t = fCompletion * 0.01f,
83 size = std::max(1.0f, fWidth),
84 angle = SkDegreesToRadians(-fDirection),
85 feather = std::max(fFeather * kFeatherSigmaFactor, kMinFeather),
86 df = feather / size, // feather distance in normalized stop space
87 df0 = 0.5f * std::min(df, t),
88 df1 = 0.5f * std::min(df, 1 - t);
89
90 // In its simplest form, the Venetian Blinds effect is a single-step gradient
91 // repeating along the direction vector.
92 //
93 // To avoid an expensive blur pass, we emulate the feather property by softening
94 // the gradient edges:
95 //
96 // 1.0 [ | ------- ]
97 // [ | / \ ]
98 // [ | / \ ]
99 // [ | / \ ]
100 // [ | / \ ]
101 // [ | / \ ]
102 // [ | / \ ]
103 // [ |/ \]
104 // 0.5 [ | ]
105 // [\ /| ]
106 // [ \ / | ]
107 // [ \ / | ]
108 // [ \ / | ]
109 // [ \ / | ]
110 // [ \ / | ]
111 // [ \ / | ]
112 // 0.0 [ ------------------- | ]
113 //
114 // ^ ^ ^ ^ ^ ^ ^
115 // 0 fp0 fp1 T fp2 fp3 1
116 //
117 // | | | | | | |
118 // |< df0 >| |< df0 >|< df1 >| |< df1 >|
119 //
120 // ... df >| |< df >| |< df ...
121 //
122 // Note 1: fp0-fp1 and/or fp2-fp3 can collapse when df is large enough.
123 //
124 // Note 2: G(fp0) == G(fp1) and G(fp2) == G(fp3), whether collapsed or not.
125 //
126 // Note 3: to minimize the number of gradient stops, we can shift the gradient by -df0
127 // (such that fp0 aligns with 0/pts[0]).
128
129 // Gradient value at fp0/fp1, fp2/fp3.
130 // Note: g01 > 0 iff fp0-fp1 is collapsed and g23 < 1 iff fp2-fp3 is collapsed
131 const auto g01 = std::max(0.0f, 0.5f * (1 + sk_ieee_float_divide(0 - t, df))),
132 g23 = std::min(1.0f, 0.5f * (1 + sk_ieee_float_divide(1 - t, df)));
133 SkASSERT(0 <= g01 && g01 <= g23 && g23 <= 1);
134
135 const SkColor c01 = SkColorSetA(SK_ColorWHITE, SkScalarRoundToInt(g01 * 0xff)),
136 c23 = SkColorSetA(SK_ColorWHITE, SkScalarRoundToInt(g23 * 0xff)),
137 colors[] = { c01, c23, c23, c01 };
138
139 const SkScalar pos[] = {
140 // 0, // fp0
141 t - df0 - df0, // fp1
142 t + df1 - df0, // fp2
143 1 - df1 - df0, // fp3
144 1,
145 };
146 static_assert(std::size(colors) == std::size(pos), "");
147
148 const auto center = SkPoint::Make(0.5f * this->layerSize().width(),
149 0.5f * this->layerSize().height()),
150 grad_vec = SkVector::Make( size * std::cos(angle),
151 -size * std::sin(angle));
152
153 const SkPoint pts[] = {
154 center + grad_vec * (df0 + 0),
155 center + grad_vec * (df0 + 1),
156 };
157
158 return {
159 SkGradientShader::MakeLinear(pts, colors, pos, std::size(colors),
161 true
162 };
163 }
164
165 ScalarValue fCompletion = 0,
166 fDirection = 0,
167 fWidth = 0,
168 fFeather = 0;
169
170 using INHERITED = MaskShaderEffectBase;
171};
172
173} // namespace
174
175sk_sp<sksg::RenderNode> EffectBuilder::attachVenetianBlindsEffect(
176 const skjson::ArrayValue& jprops, sk_sp<sksg::RenderNode> layer) const {
177 return fBuilder->attachDiscardableAdapter<VenetianBlindsAdapter>(jprops,
178 std::move(layer),
179 fLayerSize,
180 fBuilder);
181}
182
183} // namespace internal
184} // namespace skottie
SkPoint pos
#define SkASSERT(cond)
Definition SkAssert.h:116
uint32_t SkColor
Definition SkColor.h:37
constexpr SkColor SK_ColorTRANSPARENT
Definition SkColor.h:99
static constexpr SkColor SkColorSetA(SkColor c, U8CPU a)
Definition SkColor.h:82
constexpr SkColor SK_ColorWHITE
Definition SkColor.h:122
static constexpr float sk_ieee_float_divide(float numer, float denom)
static std::unique_ptr< SkEncoder > Make(SkWStream *dst, const SkPixmap *src, const SkYUVAPixmaps *srcYUVA, const SkColorSpace *srcYUVAColorSpace, const SkJpegEncoder::Options &options)
#define INHERITED(method,...)
#define SkDegreesToRadians(degrees)
Definition SkScalar.h:77
#define SkScalarRoundToInt(x)
Definition SkScalar.h:37
static SkScalar center(float pos0, float pos1)
static sk_sp< SkShader > MakeLinear(const SkPoint pts[2], const SkColor colors[], const SkScalar pos[], int count, SkTileMode mode, uint32_t flags=0, const SkMatrix *localMatrix=nullptr)
void attachDiscardableAdapter(sk_sp< T > adapter) const
float SkScalar
Definition extension.cpp:12
PODArray< SkColor > colors
Definition SkRecords.h:276
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
SkScalar ScalarValue
Definition ref_ptr.h:256
int32_t height
int32_t width
static constexpr SkPoint Make(float x, float y)