Add out of band loading to rive-wasm
Draft, as there's a quite a few bits to do, but would be neat to get thoughts on it
it "works" but there are questions.
- [x] clean up commits a bit
- [x] pull out cdn stuff to pr that alone & unblock @umberto-sonnino
- [x] make prettier example, i think something with a few images is going to work well
- [x] sort out cpp api for decoding assets. dart lets you set the image, i think cpp needs to do the same. (rather than make it implement decode as it currently does)
- [x] asyncify?! ( we are not doing this at this point)
- [x] make fonts replaceable
- [x] fonts do not replace after rendering/ sometimes async fonts do not get drawn (will tackle this later, need to add artboard referencers to assets so that we know what needs to be made dirty once they are updated)
- [x] fix tests
- [x] add tests
- [x] test webgl
- [x] figure out caching (pushed off for later pr)
example looks a bit like this:
https://github.com/rive-app/rive/assets/1216025/98bc1eaf-6076-44d2-93ca-a9cc8ea42f9e
but it can look like this if the fonts do not load properly

(to repro ☝️ set latency to 300ms)
to run.
compile wasm
`cd rive/packages/runtime_wasm/wasm` && `./build_all_wasm.sh`
run the example
`cd rive/packages/runtime_wasm/wasm/examples/out_of_band_example` && `npm start` (oh and `npm install` first)
Diffs=
f95f54140 Add out of band loading to rive-wasm (#6017)
Co-authored-by: Maxwell Talbot <talbot.maxwell@gmail.com>
diff --git a/.rive_head b/.rive_head
index 6949616..aec9b2c 100644
--- a/.rive_head
+++ b/.rive_head
@@ -1 +1 @@
-54d736fec499e15bcd2420e61cd370bf11b9b70c
+f95f54140657f8b8726392a3d0b4036bb4ad70fb
diff --git a/include/rive/file_asset_loader.hpp b/include/rive/file_asset_loader.hpp
index 201d5a3..32136bb 100644
--- a/include/rive/file_asset_loader.hpp
+++ b/include/rive/file_asset_loader.hpp
@@ -3,6 +3,7 @@
#include <cstdint>
#include <vector>
+#include "rive/span.hpp"
namespace rive
{
@@ -12,21 +13,14 @@
public:
virtual ~FileAssetLoader() {}
- /// The return value sets the intention for handling loading the contents
- /// of the given asset. When no asset loader commits to handling the contents
- /// we will load assets in band if provided.
- ///
- /// @param asset describes the asset that Rive is looking for the
- /// contents of.
- virtual bool willLoadContents(FileAsset& asset) {
- return true;
- }
-
/// Load the contents of the given asset
///
/// @param asset describes the asset that Rive is looking for the
- /// contents of.
- virtual void loadContents(FileAsset& asset) = 0;
+ /// contents of.
+ /// @param inBandBytes is a pointer to the bytes in question
+ /// @returns bool indicating if we are loading or have loaded the contents
+
+ virtual bool loadContents(FileAsset& asset, Span<const uint8_t> inBandBytes) = 0;
};
} // namespace rive
#endif
diff --git a/include/rive/relative_local_asset_loader.hpp b/include/rive/relative_local_asset_loader.hpp
index 17b84a0..30d7d8a 100644
--- a/include/rive/relative_local_asset_loader.hpp
+++ b/include/rive/relative_local_asset_loader.hpp
@@ -5,6 +5,7 @@
#include "rive/assets/file_asset.hpp"
#include <cstdio>
#include <string>
+#include "rive/span.hpp"
namespace rive
{
@@ -30,7 +31,7 @@
}
}
- void loadContents(FileAsset& asset) override
+ bool loadContents(FileAsset& asset, Span<const uint8_t> inBandBytes) override
{
std::string filename = m_Path + asset.uniqueFilename();
FILE* fp = fopen(filename.c_str(), "rb");
@@ -44,6 +45,7 @@
asset.decode(Span<const uint8_t>(bytes, length), m_Factory);
}
delete[] bytes;
+ return true;
}
};
} // namespace rive
diff --git a/skia/dependencies/make_skia_wasm.sh b/skia/dependencies/make_skia_wasm.sh
index 53fe254..81b47c5 100755
--- a/skia/dependencies/make_skia_wasm.sh
+++ b/skia/dependencies/make_skia_wasm.sh
@@ -2,7 +2,7 @@
set -e
-# Requires depot_tools and git:
+# Requires depot_tools and git:
# https://skia.org/user/download
# Build notes:
# https://skia.org/user/build
@@ -37,8 +37,9 @@
skia_use_icu=false \
skia_use_libheif=false \
skia_use_system_libpng=false \
+ skia_use_system_libjpeg_turbo=false \
skia_use_libjpeg_turbo_encode=false \
- skia_use_libjpeg_turbo_decode=false \
+ skia_use_libjpeg_turbo_decode=true \
skia_use_libwebp_encode=false \
skia_use_libwebp_decode=false \
skia_use_lua=false \
@@ -59,6 +60,7 @@
skia_enable_tools = false \
skia_enable_skgpu_v1 = true \
"
+
ninja -C out/wasm libskia.a
du -hs out/wasm/libskia.a
diff --git a/skia/renderer/src/skia_factory.cpp b/skia/renderer/src/skia_factory.cpp
index 67394d4..96e70b5 100644
--- a/skia/renderer/src/skia_factory.cpp
+++ b/skia/renderer/src/skia_factory.cpp
@@ -284,12 +284,12 @@
std::unique_ptr<RenderImage> SkiaFactory::decodeImage(Span<const uint8_t> encoded)
{
- sk_sp<SkData> data = SkData::MakeWithoutCopy(encoded.data(), encoded.size());
+ sk_sp<SkData> data = SkData::MakeWithCopy(encoded.data(), encoded.size());
auto image = SkImage::MakeFromEncoded(data);
if (image)
{
- // Our optimized skia buld seems to have broken lazy-image decode.
+ // Our optimized skia build seems to have broken lazy-image decode.
// As a work-around for now, force the image to be decoded.
image = image->makeRasterImage();
}
diff --git a/src/importers/file_asset_importer.cpp b/src/importers/file_asset_importer.cpp
index f7d8ffd..545b462 100644
--- a/src/importers/file_asset_importer.cpp
+++ b/src/importers/file_asset_importer.cpp
@@ -24,18 +24,23 @@
StatusCode FileAssetImporter::resolve()
{
- // If we have a file asset loader that commits to loading the file asset, let it handle it
- if (m_FileAssetLoader != nullptr && m_FileAssetLoader->willLoadContents(*m_FileAsset))
+
+ Span<const uint8_t> bytes;
+ if (m_Content != nullptr)
{
- m_FileAssetLoader->loadContents(*m_FileAsset);
- }
- // If we do not, but we have found in band contents, load those
- else if (m_Content != nullptr)
- {
- auto data = m_Content->bytes();
- m_FileAsset->decode(data, m_Factory);
+ bytes = m_Content->bytes();
}
+ // If we have a file asset loader, lets give it the opportunity to claim responsibility for loading the asset
+ if (m_FileAssetLoader != nullptr && m_FileAssetLoader->loadContents(*m_FileAsset, bytes))
+ {
+ return StatusCode::Ok;
+ }
+ // If we do not, but we have found in band contents, load those
+ else if (bytes.size() > 0){
+ m_FileAsset->decode(bytes, m_Factory);
+ }
+
// Note that it's ok for an asset to not resolve (or to resolve async).
return StatusCode::Ok;
}
diff --git a/test/in_band_asset_load_test.cpp b/test/in_band_asset_load_test.cpp
index c4b9587..b9a50c5 100644
--- a/test/in_band_asset_load_test.cpp
+++ b/test/in_band_asset_load_test.cpp
@@ -2,6 +2,7 @@
#include <rive/bones/tendon.hpp>
#include <rive/file.hpp>
#include <rive/node.hpp>
+#include <rive/span.hpp>
#include <rive/shapes/clipping_shape.hpp>
#include <rive/shapes/path_vertex.hpp>
#include <rive/shapes/points_path.hpp>
@@ -16,6 +17,32 @@
#include <catch.hpp>
#include <cstdio>
+
+class PretendAssetLoader : public rive ::FileAssetLoader
+{
+
+public:
+ rive::FileAsset* attemptedAsset;
+
+ bool loadContents(rive::FileAsset& asset, rive::Span<const uint8_t> inBandBytes) override
+ {
+ attemptedAsset = &asset;
+ return true;
+ }
+};
+
+class RejectAssetLoader : public rive ::FileAssetLoader
+{
+
+public:
+ rive::FileAsset* attemptedAsset;
+
+ bool loadContents(rive::FileAsset& asset, rive::Span<const uint8_t> inBandBytes) override
+ {
+ return false;
+ }
+};
+
TEST_CASE("Load asset with in-band image", "[asset]")
{
auto file = ReadRiveFile("../../test/assets/in_band_asset.riv");
@@ -38,19 +65,10 @@
REQUIRE(firstAsset->as<rive::ImageAsset>()->decodedByteSize == 308);
}
-class TestAssetLoader : public rive ::FileAssetLoader
+
+TEST_CASE("Load asset with in-band image, passing responsibility to loader", "[asset]")
{
-
-public:
- rive::FileAsset* attemptedAsset;
-
- bool willLoadContents(rive::FileAsset& asset) override { return true; }
- void loadContents(rive::FileAsset& asset) override { attemptedAsset = &asset; }
-};
-
-TEST_CASE("Load asset with in-band image, disabling loading in band assets", "[asset]")
-{
- auto loader = TestAssetLoader();
+ auto loader = PretendAssetLoader();
// our Loader has not attempted to load any asset.
REQUIRE(loader.attemptedAsset == nullptr);
@@ -84,3 +102,14 @@
REQUIRE(loader.attemptedAsset->uniqueFilename() == "1x1-45022.png");
REQUIRE(loader.attemptedAsset->fileExtension() == "png");
}
+
+TEST_CASE("Load asset with in-band image, rejecting the loading responsiblity as loader", "[asset]")
+{
+ auto loader = RejectAssetLoader();
+ auto file = ReadRiveFile("../../test/assets/in_band_asset.riv", nullptr, &loader);
+ auto assets = file->assets();
+ auto firstAsset = assets[0];
+ REQUIRE(firstAsset->is<rive::ImageAsset>());
+ // our loader does not handle loading the asset, so we load the in band contents.
+ REQUIRE(firstAsset->as<rive::ImageAsset>()->decodedByteSize == 308);
+}