Flutter Engine
The Flutter Engine
SlideDir.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2018 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
9
13#include "include/core/SkFont.h"
15#include "include/core/SkRect.h"
34
35#include <cmath>
36#include <utility>
37
38namespace sksg { class InvalidationController; }
39
40using namespace skia_private;
41
43public:
44 Animator(const Animator&) = delete;
45 Animator& operator=(const Animator&) = delete;
46
47 void tick(float t) { this->onTick(t); }
48
49protected:
50 Animator() = default;
51
52 virtual void onTick(float t) = 0;
53};
54
55namespace {
56
57static constexpr float kAspectRatio = 1.5f;
58static constexpr float kLabelSize = 12.0f;
59static constexpr SkSize kPadding = { 12.0f , 24.0f };
60
61static constexpr float kFocusDuration = 500;
62static constexpr SkSize kFocusInset = { 100.0f, 100.0f };
63static constexpr SkPoint kFocusCtrl0 = { 0.3f, 1.0f };
64static constexpr SkPoint kFocusCtrl1 = { 0.0f, 1.0f };
65static constexpr SkColor kFocusShade = 0xa0000000;
66
67// TODO: better unfocus binding?
68static constexpr SkUnichar kUnfocusKey = ' ';
69
70class SlideAdapter final : public sksg::RenderNode {
71public:
72 explicit SlideAdapter(sk_sp<Slide> slide)
73 : fSlide(std::move(slide)) {
74 SkASSERT(fSlide);
75 }
76
77 sk_sp<SlideDir::Animator> makeForwardingAnimator() {
78 // Trivial sksg::Animator -> skottie::Animation tick adapter
79 class ForwardingAnimator final : public SlideDir::Animator {
80 public:
81 explicit ForwardingAnimator(sk_sp<SlideAdapter> adapter)
82 : fAdapter(std::move(adapter)) {}
83
84 protected:
85 void onTick(float t) override {
86 fAdapter->tick(SkScalarRoundToInt(t));
87 }
88
89 private:
90 sk_sp<SlideAdapter> fAdapter;
91 };
92
93 return sk_make_sp<ForwardingAnimator>(sk_ref_sp(this));
94 }
95
96protected:
98 const auto isize = fSlide->getDimensions();
99 return SkRect::MakeIWH(isize.width(), isize.height());
100 }
101
102 void onRender(SkCanvas* canvas, const RenderContext* ctx) const override {
103 SkAutoCanvasRestore acr(canvas, true);
104 canvas->clipRect(SkRect::Make(fSlide->getDimensions()), true);
105
106 // TODO: commit the context?
107 fSlide->draw(canvas);
108 }
109
110 const RenderNode* onNodeAt(const SkPoint&) const override { return nullptr; }
111
112private:
113 void tick(SkMSec t) {
114 fSlide->animate(t * 1e6);
115 this->invalidate();
116 }
117
118 const sk_sp<Slide> fSlide;
119};
120
121SkMatrix SlideMatrix(const sk_sp<Slide>& slide, const SkRect& dst) {
122 const auto slideSize = slide->getDimensions();
123 return SkMatrix::RectToRect(SkRect::MakeIWH(slideSize.width(), slideSize.height()), dst,
125}
126
127} // namespace
128
134};
135
137public:
138 FocusController(const SlideDir* dir, const SkRect& focusRect)
139 : fDir(dir)
140 , fRect(focusRect)
141 , fTarget(nullptr)
142 , fMap(kFocusCtrl1, kFocusCtrl0)
143 , fState(State::kIdle) {
144 fShadePaint = sksg::Color::Make(kFocusShade);
145 fShade = sksg::Draw::Make(sksg::Plane::Make(), fShadePaint);
146 }
147
148 bool hasFocus() const { return fState == State::kFocused; }
149
150 void startFocus(const Rec* target) {
151 if (fState != State::kIdle)
152 return;
153
154 fTarget = target;
155
156 // Move the shade & slide to front.
157 fDir->fRoot->removeChild(fTarget->fSlideRoot);
158 fDir->fRoot->addChild(fShade);
159 fDir->fRoot->addChild(fTarget->fSlideRoot);
160
161 fM0 = SlideMatrix(fTarget->fSlide, fTarget->fRect);
162 fM1 = SlideMatrix(fTarget->fSlide, fRect);
163
164 fOpacity0 = 0;
165 fOpacity1 = 1;
166
167 fTimeBase = 0;
168 fState = State::kFocusing;
169
170 // Push initial state to the scene graph.
171 this->onTick(fTimeBase);
172 }
173
175 SkASSERT(fTarget);
176
177 using std::swap;
178 swap(fM0, fM1);
179 swap(fOpacity0, fOpacity1);
180
181 fTimeBase = 0;
182 fState = State::kUnfocusing;
183 }
184
186 SkASSERT(fTarget);
187
188 if (!fRect.contains(x, y)) {
189 this->startUnfocus();
190 return true;
191 }
192
193 // Map coords to slide space.
194 const auto xform = SkMatrix::RectToRect(fRect, SkRect::MakeSize(fDir->fWinSize),
196 const auto pt = xform.mapXY(x, y);
197
198 return fTarget->fSlide->onMouse(pt.x(), pt.y(), state, modifiers);
199 }
200
202 SkASSERT(fTarget);
203
204 return fTarget->fSlide->onChar(c);
205 }
206
207protected:
208 void onTick(float t) override {
209 if (!this->isAnimating())
210 return;
211
212 if (!fTimeBase) {
213 fTimeBase = t;
214 }
215
216 const auto rel_t = (t - fTimeBase) / kFocusDuration,
217 map_t = SkTPin(fMap.computeYFromX(rel_t), 0.0f, 1.0f);
218
219 SkMatrix m;
220 for (int i = 0; i < 9; ++i) {
221 m[i] = fM0[i] + map_t * (fM1[i] - fM0[i]);
222 }
223
224 SkASSERT(fTarget);
225 fTarget->fMatrix->setMatrix(m);
226
227 const auto shadeOpacity = fOpacity0 + map_t * (fOpacity1 - fOpacity0);
228 fShadePaint->setOpacity(shadeOpacity);
229
230 if (rel_t < 1)
231 return;
232
233 switch (fState) {
234 case State::kFocusing:
235 fState = State::kFocused;
236 break;
237 case State::kUnfocusing:
238 fState = State::kIdle;
239 fDir->fRoot->removeChild(fShade);
240 break;
241
242 case State::kIdle:
243 case State::kFocused:
244 SkASSERT(false);
245 break;
246 }
247 }
248
249private:
250 enum class State {
251 kIdle,
252 kFocusing,
253 kUnfocusing,
254 kFocused,
255 };
256
257 bool isAnimating() const { return fState == State::kFocusing || fState == State::kUnfocusing; }
258
259 const SlideDir* fDir;
260 const SkRect fRect;
261 const Rec* fTarget;
262
263 SkCubicMap fMap;
265 sk_sp<sksg::PaintNode> fShadePaint;
266
267 SkMatrix fM0 = SkMatrix::I(),
268 fM1 = SkMatrix::I();
269 float fOpacity0 = 0,
270 fOpacity1 = 1,
271 fTimeBase = 0;
272 State fState = State::kIdle;
273};
274
275SlideDir::SlideDir(const SkString& name, TArray<sk_sp<Slide>>&& slides, int columns)
276 : fSlides(std::move(slides))
277 , fColumns(columns) {
278 fName = name;
279}
280
282 const SkPoint& pos,
283 const SkMatrix& dstXform) {
284 const auto size = kLabelSize / std::sqrt(dstXform.getScaleX() * dstXform.getScaleY());
285 auto text = sksg::Text::Make(nullptr, txt);
287 text->setSize(size);
289 text->setPosition(pos + SkPoint::Make(0, size));
290
292}
293
294void SlideDir::load(SkScalar winWidth, SkScalar winHeight) {
295 // Build a global scene using transformed animation fragments:
296 //
297 // [Group(root)]
298 // [Transform]
299 // [Group]
300 // [AnimationWrapper]
301 // [Draw]
302 // [Text]
303 // [Color]
304 // [Transform]
305 // [Group]
306 // [AnimationWrapper]
307 // [Draw]
308 // [Text]
309 // [Color]
310 // ...
311 //
312
313 fWinSize = SkSize::Make(winWidth, winHeight);
314 const auto cellWidth = winWidth / fColumns;
315 fCellSize = SkSize::Make(cellWidth, cellWidth / kAspectRatio);
316
317 fRoot = sksg::Group::Make();
318
319 for (int i = 0; i < fSlides.size(); ++i) {
320 const auto& slide = fSlides[i];
321 slide->load(winWidth, winHeight);
322
323 const auto slideSize = slide->getDimensions();
324 const auto cell = SkRect::MakeXYWH(fCellSize.width() * (i % fColumns),
325 fCellSize.height() * (i / fColumns),
326 fCellSize.width(),
327 fCellSize.height()),
328 slideRect = cell.makeInset(kPadding.width(), kPadding.height());
329
330 auto slideMatrix = sksg::Matrix<SkMatrix>::Make(SlideMatrix(slide, slideRect));
331 auto adapter = sk_make_sp<SlideAdapter>(slide);
332 auto slideGrp = sksg::Group::Make();
333 slideGrp->addChild(sksg::Draw::Make(sksg::Rect::Make(SkRect::MakeIWH(slideSize.width(),
334 slideSize.height())),
335 sksg::Color::Make(0xfff0f0f0)));
336 slideGrp->addChild(adapter);
337 slideGrp->addChild(MakeLabel(slide->getName(),
338 SkPoint::Make(slideSize.width() / 2, slideSize.height()),
339 slideMatrix->getMatrix()));
340 auto slideRoot = sksg::TransformEffect::Make(std::move(slideGrp), slideMatrix);
341
342 fSceneAnimators.push_back(adapter->makeForwardingAnimator());
343
344 fRoot->addChild(slideRoot);
345 fRecs.push_back({ slide, slideRoot, slideMatrix, slideRect });
346 }
347
348 fScene = sksg::Scene::Make(fRoot);
349
350 const auto focusRect = SkRect::MakeSize(fWinSize).makeInset(kFocusInset.width(),
351 kFocusInset.height());
352 fFocusController = std::make_unique<FocusController>(this, focusRect);
353}
354
356 for (const auto& slide : fSlides) {
357 slide->unload();
358 }
359
360 fRecs.clear();
361 fScene.reset();
362 fFocusController.reset();
363 fRoot.reset();
364 fTimeBase = 0;
365}
366
368 return SkSize::Make(fWinSize.width(),
369 fCellSize.height() * (1 + (fSlides.size() - 1) / fColumns)).toCeil();
370}
371
373 fScene->render(canvas);
374}
375
376bool SlideDir::animate(double nanos) {
377 SkMSec msec = TimeUtils::NanosToMSec(nanos);
378 if (fTimeBase == 0) {
379 // Reset the animation time.
380 fTimeBase = msec;
381 }
382
383 const auto t = msec - fTimeBase;
384 for (const auto& anim : fSceneAnimators) {
385 anim->tick(t);
386 }
387 fFocusController->tick(t);
388
389 return true;
390}
391
393 if (fFocusController->hasFocus()) {
394 if (c == kUnfocusKey) {
395 fFocusController->startUnfocus();
396 return true;
397 }
398 return fFocusController->onChar(c);
399 }
400
401 return false;
402}
403
405 skui::ModifierKey modifiers) {
406 modifiers &= ~skui::ModifierKey::kFirstPress;
407 if (state == skui::InputState::kMove || sknonstd::Any(modifiers))
408 return false;
409
410 if (fFocusController->hasFocus()) {
411 return fFocusController->onMouse(x, y, state, modifiers);
412 }
413
414 const auto* cell = this->findCell(x, y);
415 if (!cell)
416 return false;
417
418 static constexpr SkScalar kClickMoveTolerance = 4;
419
420 switch (state) {
422 fTrackingCell = cell;
423 fTrackingPos = SkPoint::Make(x, y);
424 break;
426 if (cell == fTrackingCell &&
427 SkPoint::Distance(fTrackingPos, SkPoint::Make(x, y)) < kClickMoveTolerance) {
428 fFocusController->startFocus(cell);
429 }
430 break;
431 default:
432 break;
433 }
434
435 return false;
436}
437
438const SlideDir::Rec* SlideDir::findCell(float x, float y) const {
439 // TODO: use SG hit testing instead of layout info?
440 const auto size = this->getDimensions();
441 if (x < 0 || y < 0 || x >= size.width() || y >= size.height()) {
442 return nullptr;
443 }
444
445 const int col = static_cast<int>(x / fCellSize.width()),
446 row = static_cast<int>(y / fCellSize.height()),
447 idx = row * fColumns + col;
448
449 return idx < (int)fRecs.size() ? &fRecs[idx] : nullptr;
450}
SkPoint pos
#define SkASSERT(cond)
Definition: SkAssert.h:116
uint32_t SkColor
Definition: SkColor.h:37
constexpr SkColor SK_ColorBLACK
Definition: SkColor.h:103
sk_sp< T > sk_ref_sp(T *obj)
Definition: SkRefCnt.h:381
void swap(sk_sp< T > &a, sk_sp< T > &b)
Definition: SkRefCnt.h:341
#define SkScalarRoundToInt(x)
Definition: SkScalar.h:37
static constexpr const T & SkTPin(const T &x, const T &lo, const T &hi)
Definition: SkTPin.h:19
int32_t SkUnichar
Definition: SkTypes.h:175
uint32_t SkMSec
Definition: SkTypes.h:184
static sk_sp< sksg::RenderNode > MakeLabel(const SkString &txt, const SkPoint &pos, const SkMatrix &dstXform)
Definition: SlideDir.cpp:281
void clipRect(const SkRect &rect, SkClipOp op, bool doAntiAlias)
Definition: SkCanvas.cpp:1361
float computeYFromX(float x) const
Definition: SkCubicMap.cpp:61
@ kAntiAlias
may have transparent pixels on glyph edges
static SkMatrix RectToRect(const SkRect &src, const SkRect &dst, ScaleToFit mode=kFill_ScaleToFit)
Definition: SkMatrix.h:157
@ kCenter_ScaleToFit
scales and aligns to center
Definition: SkMatrix.h:139
SkScalar getScaleX() const
Definition: SkMatrix.h:415
static const SkMatrix & I()
Definition: SkMatrix.cpp:1544
SkScalar getScaleY() const
Definition: SkMatrix.h:422
void tick(float t)
Definition: SlideDir.cpp:47
virtual void onTick(float t)=0
Animator(const Animator &)=delete
Animator & operator=(const Animator &)=delete
bool onChar(SkUnichar c)
Definition: SlideDir.cpp:201
void onTick(float t) override
Definition: SlideDir.cpp:208
bool onMouse(SkScalar x, SkScalar y, skui::InputState state, skui::ModifierKey modifiers)
Definition: SlideDir.cpp:185
FocusController(const SlideDir *dir, const SkRect &focusRect)
Definition: SlideDir.cpp:138
void startFocus(const Rec *target)
Definition: SlideDir.cpp:150
SlideDir(const SkString &name, skia_private::TArray< sk_sp< Slide > > &&, int columns=kDefaultColumnCount)
Definition: SlideDir.cpp:275
void load(SkScalar winWidth, SkScalar winHeight) override
Definition: SlideDir.cpp:294
void draw(SkCanvas *) override
Definition: SlideDir.cpp:372
bool onChar(SkUnichar) override
Definition: SlideDir.cpp:392
bool animate(double) override
Definition: SlideDir.cpp:376
SkISize getDimensions() const override
Definition: SlideDir.cpp:367
void unload() override
Definition: SlideDir.cpp:355
bool onMouse(SkScalar x, SkScalar y, skui::InputState, skui::ModifierKey modifiers) override
Definition: SlideDir.cpp:404
virtual bool onMouse(SkScalar x, SkScalar y, skui::InputState state, skui::ModifierKey modifiers)
Definition: Slide.h:45
virtual void unload()
Definition: Slide.h:42
virtual bool onChar(SkUnichar c)
Definition: Slide.h:44
SkString fName
Definition: Slide.h:54
virtual SkISize getDimensions() const
Definition: Slide.h:35
const SkString & getName()
Definition: Slide.h:51
virtual void load(SkScalar winWidth, SkScalar winHeight)
Definition: Slide.h:40
void reset(T *ptr=nullptr)
Definition: SkRefCnt.h:310
int size() const
Definition: SkTArray.h:421
static sk_sp< Color > Make(SkColor c)
Definition: SkSGPaint.cpp:44
static sk_sp< Draw > Make(sk_sp< GeometryNode > geo, sk_sp< PaintNode > paint)
Definition: SkSGDraw.h:35
void removeChild(const sk_sp< RenderNode > &)
Definition: SkSGGroup.cpp:59
void addChild(sk_sp< RenderNode >)
Definition: SkSGGroup.cpp:45
static sk_sp< Group > Make()
Definition: SkSGGroup.h:31
static sk_sp< Matrix > Make(const T &m)
Definition: SkSGTransform.h:70
void invalidate(bool damage=true)
Definition: SkSGNode.cpp:113
virtual SkRect onRevalidate(InvalidationController *, const SkMatrix &ctm)=0
static sk_sp< Plane > Make()
Definition: SkSGPlane.h:29
static sk_sp< Rect > Make()
Definition: SkSGRect.h:36
virtual const RenderNode * onNodeAt(const SkPoint &p) const =0
virtual void onRender(SkCanvas *, const RenderContext *) const =0
static std::unique_ptr< Scene > Make(sk_sp< RenderNode > root)
Definition: SkSGScene.cpp:16
static sk_sp< Text > Make(sk_sp< SkTypeface > tf, const SkString &text)
Definition: SkSGText.cpp:21
static sk_sp< TransformEffect > Make(sk_sp< RenderNode > child, sk_sp< Transform > transform)
Definition: SkSGTransform.h:97
float SkScalar
Definition: extension.cpp:12
AtkStateType state
uint32_t * target
static const int kLabelSize
Definition: flippity.cpp:45
std::u16string text
double y
double x
static SkMSec NanosToMSec(double nanos)
Definition: TimeUtils.h:16
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets dir
Definition: switches.h:145
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
dst
Definition: cp.py:12
constexpr auto kPadding
std::enable_if_t< sknonstd::is_bitmask_enum< E >::value, bool > constexpr Any(E e)
Definition: SkBitmaskEnum.h:16
Definition: Skottie.h:32
InputState
Definition: InputState.h:6
ModifierKey
Definition: ModifierKey.h:9
SIN Vec< N, float > sqrt(const Vec< N, float > &x)
Definition: SkVx.h:706
Definition: ref_ptr.h:256
Definition: SkSize.h:16
static constexpr SkPoint Make(float x, float y)
Definition: SkPoint_impl.h:173
static float Distance(const SkPoint &a, const SkPoint &b)
Definition: SkPoint_impl.h:508
static SkRect Make(const SkISize &size)
Definition: SkRect.h:669
static SkRect MakeIWH(int w, int h)
Definition: SkRect.h:623
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition: SkRect.h:659
SkRect makeInset(float dx, float dy) const
Definition: SkRect.h:987
bool contains(SkScalar x, SkScalar y) const
Definition: extension.cpp:19
static constexpr SkRect MakeSize(const SkSize &size)
Definition: SkRect.h:633
Definition: SkSize.h:52
static constexpr SkSize Make(SkScalar w, SkScalar h)
Definition: SkSize.h:56
SkISize toCeil() const
Definition: SkSize.h:83
SkScalar width() const
Definition: SkSize.h:76
SkScalar height() const
Definition: SkSize.h:77
sk_sp< sksg::RenderNode > fSlideRoot
Definition: SlideDir.cpp:131
SkRect fRect
Definition: SlideDir.cpp:133
sk_sp< sksg::Matrix< SkMatrix > > fMatrix
Definition: SlideDir.cpp:132
sk_sp< Slide > fSlide
Definition: SlideDir.cpp:130