Add hook for platform codec support

Add virtual to our Skia Factory to allow clients to give us access to the Platform's native codecs.

Targeted for Android and iOS, where we'll have to do some marshaling between C++ and the host languages. However, if it works there, we can consider removing some of the codecs currently backed into our Skia build.

For power-users in the Editor, we can document that we support *all* image formats on the respective platforms, in case they want to take advantage of a specific format on a given platform (e.g. HEIF on iOS).

Viewer change:

To test the viability, viewer is modified to call into Skia's wrapper for CGImageSource. This is the Mac/iOS native image decoder. Thus viewer now has access to all of the platform's image formats.

Diffs=
300e4dc14 Add hook for platform codec support
diff --git a/.rive_head b/.rive_head
index b2ce439..d271d13 100644
--- a/.rive_head
+++ b/.rive_head
@@ -1 +1 @@
-8aed176883c0cce64c82d48b6739718935be58d1
+300e4dc14bafeebdb7c378e28b2098688891f14e
diff --git a/skia/renderer/include/skia_factory.hpp b/skia/renderer/include/skia_factory.hpp
index 9b145bb..22c432e 100644
--- a/skia/renderer/include/skia_factory.hpp
+++ b/skia/renderer/include/skia_factory.hpp
@@ -6,6 +6,7 @@
 #define _RIVE_SKIA_FACTORY_HPP_
 
 #include "rive/factory.hpp"
+#include <vector>
 
 namespace rive {
 
@@ -38,6 +39,34 @@
     std::unique_ptr<RenderPaint> makeRenderPaint() override;
 
     std::unique_ptr<RenderImage> decodeImage(Span<const uint8_t>) override;
+
+    //
+    // New virtual for access the platform's codecs
+    //
+
+public:
+    enum class ColorType {
+        rgba,
+        bgra,
+    };
+    enum class AlphaType {
+        premul,
+        opaque,
+    };
+    struct ImageInfo {
+        size_t      rowBytes;   // number of bytes between rows
+        uint32_t    width;      // logical width in pixels
+        uint32_t    height;     // logical height in pixels
+        ColorType   colorType;
+        AlphaType   alphaType;
+    };
+
+    // Clients can override this to provide access to the platform's decoders, rather
+    // than solely relying on the codecs built into Skia. This allows for the Skia impl
+    // to not have to duplicate the code for codecs that the platform may already have.
+    virtual std::vector<uint8_t> platformDecode(Span<const uint8_t>, ImageInfo* info) {
+        return std::vector<uint8_t>();  // empty vector means decode failed
+    }
 };
 
 } // namespace rive
diff --git a/skia/renderer/src/skia_factory.cpp b/skia/renderer/src/skia_factory.cpp
index 071da4d..9a33026 100644
--- a/skia/renderer/src/skia_factory.cpp
+++ b/skia/renderer/src/skia_factory.cpp
@@ -314,10 +314,22 @@
     sk_sp<SkData> data = SkData::MakeWithoutCopy(encoded.data(), encoded.size());
     auto image = SkImage::MakeFromEncoded(data);
 
-    // Our optimized skia buld seems to have broken lazy-image decode.
-    // As a work-around for now, force the image to be decoded.
     if (image) {
+        // Our optimized skia buld seems to have broken lazy-image decode.
+        // As a work-around for now, force the image to be decoded.
         image = image->makeRasterImage();
+    } else {
+        // Skia failed, so let's try the platform
+        ImageInfo info;
+        auto pixels = this->platformDecode(encoded, &info);
+        if (pixels.size() > 0) {
+            auto ct = info.colorType == ColorType::rgba ? kRGBA_8888_SkColorType
+                                                        : kBGRA_8888_SkColorType;
+            auto at = info.alphaType == AlphaType::premul ? kPremul_SkAlphaType
+                                                          : kOpaque_SkAlphaType;
+            auto skinfo = SkImageInfo::Make(info.width, info.height, ct, at);
+            image = SkImage::MakeRasterCopy({skinfo, pixels.data(), info.rowBytes});
+        }
     }
 
     return image ? std::make_unique<SkiaRenderImage>(std::move(image)) : nullptr;
diff --git a/skia/viewer/src/main.cpp b/skia/viewer/src/main.cpp
index 8c37915..6824203 100644
--- a/skia/viewer/src/main.cpp
+++ b/skia/viewer/src/main.cpp
@@ -34,7 +34,35 @@
 #include <cmath>
 #include <stdio.h>
 
-rive::SkiaFactory skiaFactory;
+#include "include/ports/SkImageGeneratorCG.h"
+#include "include/core/SkImageInfo.h"
+// Exercise our platformDecode() virtual by calling CGImageSource
+// ... via SkImageGeneratorCG.
+struct Skia2Factory : public rive::SkiaFactory {
+    std::vector<uint8_t> platformDecode(rive::Span<const uint8_t> span, ImageInfo* info) override {
+        std::vector<uint8_t> pixels;
+        auto data = SkData::MakeWithoutCopy(span.data(), span.size());
+        auto gen = SkImageGeneratorCG::MakeFromEncodedCG(data);
+
+        if (gen) {
+            SkImageInfo skinfo = gen->getInfo();
+            info->width = skinfo.width();
+            info->height = skinfo.height();
+            info->rowBytes = skinfo.minRowBytes();
+            info->colorType = rive::SkiaFactory::ColorType::rgba; // just our choice
+            info->alphaType = skinfo.alphaType() == kOpaque_SkAlphaType ?
+                                    rive::SkiaFactory::AlphaType::opaque :
+                                    rive::SkiaFactory::AlphaType::premul;
+            size_t size = skinfo.computeMinByteSize();
+            pixels.resize(size);
+            skinfo = skinfo.makeColorType(kRGBA_8888_SkColorType);
+            gen->getPixels({skinfo, pixels.data(), info->rowBytes});
+        }
+        return pixels;
+    }
+};
+
+Skia2Factory skiaFactory;
 
 std::string filename;
 std::unique_ptr<rive::File> currentFile;