add skotty-dir slide

Shows a directory of skotties in a grid

Bug: skia:
Change-Id: I96b0700d8809c94a394cf517222123967afb20dc
Reviewed-on: https://skia-review.googlesource.com/91407
Commit-Queue: Mike Reed <reed@google.com>
Reviewed-by: Florin Malita <fmalita@chromium.org>
diff --git a/BUILD.gn b/BUILD.gn
index cc1e844..4a1433f 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1896,6 +1896,7 @@
         "tools/viewer/SKPSlide.cpp",
         "tools/viewer/SampleSlide.cpp",
         "tools/viewer/SkottySlide.cpp",
+        "tools/viewer/SkottySlide2.cpp",
         "tools/viewer/StatsLayer.cpp",
         "tools/viewer/Viewer.cpp",
       ]
diff --git a/experimental/skotty/Skotty.cpp b/experimental/skotty/Skotty.cpp
index a13a04c..84cc080 100644
--- a/experimental/skotty/Skotty.cpp
+++ b/experimental/skotty/Skotty.cpp
@@ -752,7 +752,7 @@
 
 Animation::~Animation() = default;
 
-void Animation::render(SkCanvas* canvas) const {
+void Animation::render(SkCanvas* canvas, const SkRect* dstR) const {
     if (!fDom)
         return;
 
@@ -760,6 +760,12 @@
     fDom->revalidate(&ic, SkMatrix::I());
 
     // TODO: proper inval
+    SkAutoCanvasRestore restore(canvas, true);
+    const SkRect srcR = SkRect::MakeSize(this->size());
+    if (dstR) {
+        canvas->concat(SkMatrix::MakeRectToRect(srcR, *dstR, SkMatrix::kCenter_ScaleToFit));
+    }
+    canvas->clipRect(srcR);
     fDom->render(canvas);
 
     if (!fShowInval)
diff --git a/experimental/skotty/Skotty.h b/experimental/skotty/Skotty.h
index c20feeb..d02dc8d 100644
--- a/experimental/skotty/Skotty.h
+++ b/experimental/skotty/Skotty.h
@@ -18,6 +18,7 @@
 #include <memory>
 
 class SkCanvas;
+struct SkRect;
 class SkStream;
 
 namespace Json { class Value; }
@@ -34,7 +35,7 @@
 
     ~Animation();
 
-    void render(SkCanvas*) const;
+    void render(SkCanvas*, const SkRect* dst = nullptr) const;
 
     void animationTick(SkMSec);
 
diff --git a/tools/viewer/SkottySlide.cpp b/tools/viewer/SkottySlide.cpp
index 432b307..6e3608c 100644
--- a/tools/viewer/SkottySlide.cpp
+++ b/tools/viewer/SkottySlide.cpp
@@ -44,12 +44,8 @@
 void SkottySlide::draw(SkCanvas* canvas) {
     if (fAnimation) {
         SkAutoCanvasRestore acr(canvas, true);
-        const auto animationBounds = SkRect::Make(fAnimation->size().toCeil());
-        canvas->concat(SkMatrix::MakeRectToRect(animationBounds,
-                                                SkRect::Make(canvas->imageInfo().bounds()),
-                                                SkMatrix::kCenter_ScaleToFit));
-        canvas->clipRect(animationBounds);
-        fAnimation->render(canvas);
+        const SkRect dstR = SkRect::Make(canvas->imageInfo().bounds());
+        fAnimation->render(canvas, &dstR);
     }
 }
 
diff --git a/tools/viewer/SkottySlide.h b/tools/viewer/SkottySlide.h
index 9b7ae7c..ed0662f 100644
--- a/tools/viewer/SkottySlide.h
+++ b/tools/viewer/SkottySlide.h
@@ -36,4 +36,38 @@
     typedef Slide INHERITED;
 };
 
+class SkottySlide2 : public Slide {
+public:
+    SkottySlide2(const SkString& path);
+    ~SkottySlide2() override = default;
+
+    void load(SkScalar winWidth, SkScalar winHeight) override;
+    void unload() override;
+
+    SkISize getDimensions() const override;
+
+    void draw(SkCanvas*) override;
+    bool animate(const SkAnimTimer&) override;
+    bool onMouse(SkScalar x, SkScalar y, sk_app::Window::InputState, uint32_t modifiers) override;
+private:
+    struct Rec {
+        std::unique_ptr<skotty::Animation> fAnimation;
+        SkMSec                             fTimeBase = 0;
+        SkString                           fName;
+        bool                               fShowAnimationInval = false;
+
+        Rec(std::unique_ptr<skotty::Animation> anim);
+        Rec(Rec&& o);
+    };
+
+    int findCell(float x, float y) const;
+
+    SkString        fPath;
+    SkTArray<Rec>   fAnims;
+
+    int fTrackingCell = -1;
+
+    typedef Slide INHERITED;
+};
+
 #endif // SkottySlide_DEFINED
diff --git a/tools/viewer/SkottySlide2.cpp b/tools/viewer/SkottySlide2.cpp
new file mode 100644
index 0000000..7e76693
--- /dev/null
+++ b/tools/viewer/SkottySlide2.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkottySlide.h"
+
+#include "SkAnimTimer.h"
+#include "SkCanvas.h"
+#include "Skotty.h"
+#include "SkOSFile.h"
+#include "SkOSPath.h"
+#include "SkStream.h"
+
+const int CELL_WIDTH  = 240;
+const int CELL_HEIGHT = 160;
+const int COL_COUNT   = 4;
+const int SPACER_X    = 12;
+const int SPACER_Y    = 24;
+const int MARGIN      = 8;
+
+SkottySlide2::Rec::Rec(std::unique_ptr<skotty::Animation> anim) : fAnimation(std::move(anim))
+{}
+
+SkottySlide2::Rec::Rec(Rec&& o)
+    : fAnimation(std::move(o.fAnimation))
+    , fTimeBase(o.fTimeBase)
+    , fName(o.fName)
+    , fShowAnimationInval(o.fShowAnimationInval)
+{}
+
+SkottySlide2::SkottySlide2(const SkString& path)
+    : fPath(path)
+{
+    fName.set("skotty-dir");
+}
+
+void SkottySlide2::load(SkScalar, SkScalar) {
+    SkString name;
+    SkOSFile::Iter iter(fPath.c_str(), "json");
+    while (iter.next(&name)) {
+        SkString path = SkOSPath::Join(fPath.c_str(), name.c_str());
+        if (auto stream = SkStream::MakeFromFile(path.c_str())) {
+            if (auto anim  = skotty::Animation::Make(stream.get())) {
+                fAnims.push_back(Rec(std::move(anim))).fName = name;
+            }
+        }
+    }
+}
+
+void SkottySlide2::unload() {
+    fAnims.reset();
+}
+
+SkISize SkottySlide2::getDimensions() const {
+    const int rows = (fAnims.count() + COL_COUNT - 1) / COL_COUNT;
+    return {
+        MARGIN + (COL_COUNT - 1) * SPACER_X + COL_COUNT * CELL_WIDTH + MARGIN,
+        MARGIN + (rows - 1) * SPACER_Y + rows * CELL_HEIGHT + MARGIN,
+    };
+}
+
+void SkottySlide2::draw(SkCanvas* canvas) {
+    SkPaint paint;
+    paint.setTextSize(12);
+    paint.setAntiAlias(true);
+    paint.setTextAlign(SkPaint::kCenter_Align);
+
+    const SkRect dst = SkRect::MakeIWH(CELL_WIDTH, CELL_HEIGHT);
+    int x = 0, y = 0;
+
+    canvas->translate(MARGIN, MARGIN);
+    for (const auto& rec : fAnims) {
+        SkAutoCanvasRestore acr(canvas, true);
+        canvas->translate(x * (CELL_WIDTH + SPACER_X), y * (CELL_HEIGHT + SPACER_Y));
+        canvas->drawText(rec.fName.c_str(), rec.fName.size(),
+                         dst.centerX(), dst.bottom() + paint.getTextSize(), paint);
+        rec.fAnimation->render(canvas, &dst);
+        if (++x == COL_COUNT) {
+            x = 0;
+            y += 1;
+        }
+    }
+}
+
+bool SkottySlide2::animate(const SkAnimTimer& timer) {
+    for (auto& rec : fAnims) {
+        if (rec.fTimeBase == 0) {
+            // Reset the animation time.
+            rec.fTimeBase = timer.msec();
+        }
+        rec.fAnimation->animationTick(timer.msec() - rec.fTimeBase);
+    }
+    return true;
+}
+
+bool SkottySlide2::onMouse(SkScalar x, SkScalar y, sk_app::Window::InputState state,
+                           uint32_t modifiers) {
+    if (fTrackingCell < 0 && state == sk_app::Window::kDown_InputState) {
+        fTrackingCell = this->findCell(x, y);
+    }
+    if (fTrackingCell >= 0 && state == sk_app::Window::kUp_InputState) {
+        int index = this->findCell(x, y);
+        if (fTrackingCell == index) {
+            fAnims[index].fShowAnimationInval = !fAnims[index].fShowAnimationInval;
+            fAnims[index].fAnimation->setShowInval(fAnims[index].fShowAnimationInval);
+        }
+        fTrackingCell = -1;
+    }
+    return fTrackingCell >= 0;
+}
+
+int SkottySlide2::findCell(float x, float y) const {
+    x -= MARGIN;
+    y -= MARGIN;
+    int index = -1;
+    if (x >= 0 && y >= 0) {
+        int ix = (int)x;
+        int iy = (int)y;
+        int col = ix / (CELL_WIDTH + SPACER_X);
+        int row = iy / (CELL_HEIGHT + SPACER_Y);
+        index = row * COL_COUNT + col;
+        if (index >= fAnims.count()) {
+            index = -1;
+        }
+    }
+    return index;
+}
+
diff --git a/tools/viewer/Viewer.cpp b/tools/viewer/Viewer.cpp
index 68f8a8d..59d5e50 100644
--- a/tools/viewer/Viewer.cpp
+++ b/tools/viewer/Viewer.cpp
@@ -486,6 +486,8 @@
 
     // JSONs
     for (const auto& json : FLAGS_jsons) {
+        fSlides.push_back(sk_make_sp<SkottySlide2>(json));
+
         SkOSFile::Iter it(json.c_str(), ".json");
         SkString jsonName;
         while (it.next(&jsonName)) {