Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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
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
Type::kYUV Type::kRGBA() int(0.7 *637)
static constexpr int kPadding
void clipRect(const SkRect &rect, SkClipOp op, bool doAntiAlias)
float computeYFromX(float x) const
@ 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()
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 bool onChar(SkUnichar c)
Definition Slide.h:44
SkString fName
Definition Slide.h:54
void reset(T *ptr=nullptr)
Definition SkRefCnt.h:310
int size() const
Definition SkTArray.h:416
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)
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)
float SkScalar
Definition extension.cpp:12
AtkStateType state
uint32_t * target
static const int kLabelSize
Definition flippity.cpp:45
const char * name
Definition fuchsia.cc:50
std::u16string text
double y
double x
static SkMSec NanosToMSec(double nanos)
Definition TimeUtils.h:16
std::enable_if_t< sknonstd::is_bitmask_enum< E >::value, bool > constexpr Any(E e)
Definition Skottie.h:32
InputState
Definition InputState.h:6
ModifierKey
Definition ModifierKey.h:9
Definition ref_ptr.h:256
static constexpr SkPoint Make(float x, float y)
static float Distance(const SkPoint &a, const SkPoint &b)
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
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
sk_sp< sksg::Matrix< SkMatrix > > fMatrix
Definition SlideDir.cpp:132
sk_sp< Slide > fSlide
Definition SlideDir.cpp:130