Revert "Revert "Add mskp player, use in viewer slide""

This reverts commit 0d174586c46923098eca1684e21a7049d5b62116.

Use SkTLazy instead of std::optional (C++17 library feature)

Bug: skia:11900
Change-Id: Ia41caa9322d812f9ba6644dd14ede7d0015cf8b3
Cq-Include-Trybots: luci.skia.skia.primary:Housekeeper-PerCommit-CreateDockerImage_Skia_Release,Build-Debian10-Clang-x86_64-Release-CMake
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/402642
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/tools/viewer/MSKPSlide.cpp b/tools/viewer/MSKPSlide.cpp
new file mode 100644
index 0000000..d8019b2
--- /dev/null
+++ b/tools/viewer/MSKPSlide.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2021 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "tools/viewer/MSKPSlide.h"
+
+#include "include/core/SkCanvas.h"
+#include "include/core/SkStream.h"
+#include "src/core/SkOSFile.h"
+
+MSKPSlide::MSKPSlide(const SkString& name, const SkString& path)
+        : MSKPSlide(name, SkStream::MakeFromFile(path.c_str())) {}
+
+MSKPSlide::MSKPSlide(const SkString& name, std::unique_ptr<SkStreamSeekable> stream)
+        : fStream(std::move(stream)) {
+    fName = name;
+}
+
+SkISize MSKPSlide::getDimensions() const {
+    return fPlayer ? fPlayer->maxDimensions() : SkISize{0, 0};
+}
+
+void MSKPSlide::draw(SkCanvas* canvas) {
+    if (fPlayer) {
+        fPlayer->playFrame(canvas, fFrame);
+    }
+}
+
+bool MSKPSlide::animate(double nanos) {
+    if (!fPlayer) {
+        return false;
+    }
+    double elapsed = nanos - fLastFrameTime;
+    double frameTime = 1E9/fFPS;
+    int framesToAdvance = elapsed/frameTime;
+    fFrame = (fFrame + framesToAdvance)%fPlayer->numFrames();
+    // Instead of just adding elapsed, note the time when this frame should have begun.
+    fLastFrameTime += framesToAdvance*frameTime;
+    return framesToAdvance%fPlayer->numFrames() != 0;
+}
+
+void MSKPSlide::load(SkScalar, SkScalar) {
+    if (!fStream) {
+        SkDebugf("No skp stream for slide %s.\n", fName.c_str());
+        return;
+    }
+    fStream->rewind();
+    fPlayer = MSKPPlayer::Make(fStream.get());
+    if (!fPlayer) {
+        SkDebugf("Could parse MSKP from stream for slide %s.\n", fName.c_str());
+        return;
+    }
+}
+
+void MSKPSlide::unload() { fPlayer.reset(); }
+
+void MSKPSlide::gpuTeardown() { fPlayer->resetLayers(); }
+
diff --git a/tools/viewer/MSKPSlide.h b/tools/viewer/MSKPSlide.h
new file mode 100644
index 0000000..41b3c9c
--- /dev/null
+++ b/tools/viewer/MSKPSlide.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2021 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef MSKPSlide_DEFINED
+#define MSKPSlide_DEFINED
+
+#include "tools/MSKPPlayer.h"
+#include "tools/viewer/Slide.h"
+
+class SkStreamSeekable;
+
+class MSKPSlide : public Slide {
+public:
+    MSKPSlide(const SkString& name, const SkString& path);
+    MSKPSlide(const SkString& name, std::unique_ptr<SkStreamSeekable>);
+
+    SkISize getDimensions() const override;
+
+    void draw(SkCanvas* canvas) override;
+    bool animate(double nanos) override;
+    void load(SkScalar winWidth, SkScalar winHeight) override;
+    void unload() override;
+    void gpuTeardown() override;
+
+private:
+    std::unique_ptr<SkStreamSeekable> fStream;
+    std::unique_ptr<MSKPPlayer> fPlayer;
+    int fFrame = 0;
+    int fFPS = 15;  // TODO: make this adjustable. This happens to work well for calendar.mskp
+    double fLastFrameTime = 0;
+
+    using INHERITED = Slide;
+};
+
+#endif
diff --git a/tools/viewer/Viewer.cpp b/tools/viewer/Viewer.cpp
index c30615c..82a005e 100644
--- a/tools/viewer/Viewer.cpp
+++ b/tools/viewer/Viewer.cpp
@@ -5,6 +5,8 @@
 * found in the LICENSE file.
 */
 
+#include "tools/viewer/Viewer.h"
+
 #include "include/core/SkCanvas.h"
 #include "include/core/SkData.h"
 #include "include/core/SkGraphics.h"
@@ -43,13 +45,13 @@
 #include "tools/viewer/BisectSlide.h"
 #include "tools/viewer/GMSlide.h"
 #include "tools/viewer/ImageSlide.h"
+#include "tools/viewer/MSKPSlide.h"
 #include "tools/viewer/ParticlesSlide.h"
 #include "tools/viewer/SKPSlide.h"
 #include "tools/viewer/SampleSlide.h"
 #include "tools/viewer/SkSLSlide.h"
 #include "tools/viewer/SlideDir.h"
 #include "tools/viewer/SvgSlide.h"
-#include "tools/viewer/Viewer.h"
 
 #include <cstdlib>
 #include <map>
@@ -150,19 +152,18 @@
                "it is skipped unless some list entry starts with ~");
 
 #if defined(SK_BUILD_FOR_ANDROID)
-    static DEFINE_string(jpgs, "/data/local/tmp/resources", "Directory to read jpgs from.");
-    static DEFINE_string(skps, "/data/local/tmp/skps", "Directory to read skps from.");
-    static DEFINE_string(lotties, "/data/local/tmp/lotties",
-                         "Directory to read (Bodymovin) jsons from.");
-    static DEFINE_string(rives, "/data/local/tmp/rives",
-                         "Directory to read Rive (Flare) files from.");
+#   define PATH_PREFIX "/data/local/tmp/"
 #else
-    static DEFINE_string(jpgs, "jpgs", "Directory to read jpgs from.");
-    static DEFINE_string(skps, "skps", "Directory to read skps from.");
-    static DEFINE_string(lotties, "lotties", "Directory to read (Bodymovin) jsons from.");
-    static DEFINE_string(rives, "rives", "Directory to read Rive (Flare) files from.");
+#   define PATH_PREFIX ""
 #endif
 
+static DEFINE_string(jpgs   , PATH_PREFIX "jpgs"   , "Directory to read jpgs from.");
+static DEFINE_string(skps   , PATH_PREFIX "skps"   , "Directory to read skps from.");
+static DEFINE_string(mskps  , PATH_PREFIX "mskps"  , "Directory to read mskps from.");
+static DEFINE_string(lotties, PATH_PREFIX "lotties", "Directory to read (Bodymovin) jsons from.");
+static DEFINE_string(rives  , PATH_PREFIX "rives"  , "Directory to read Rive (Flare) files from.");
+#undef PATH_PREFIX
+
 static DEFINE_string(svgs, "", "Directory to read SVGs from, or a single SVG file.");
 
 static DEFINE_int_2(threads, j, -1,
@@ -735,6 +736,10 @@
         const CommandLineFlags::StringArray&   fFlags;
         const SlideFactory                     fFactory;
     } gExternalSlidesInfo[] = {
+        { ".mskp", "mskp-dir", FLAGS_mskps,
+          [](const SkString& name, const SkString& path) -> sk_sp<Slide> {
+            return sk_make_sp<MSKPSlide>(name, path);}
+        },
         { ".skp", "skp-dir", FLAGS_skps,
             [](const SkString& name, const SkString& path) -> sk_sp<Slide> {
                 return sk_make_sp<SKPSlide>(name, path);}