@amazon-devices/expo-image 2.0.9000000000 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CMakeLists.txt +80 -58
- package/README.kepler.md +1 -0
- package/build/ExpoImageModules.kepler.d.ts.map +1 -1
- package/build/ExpoImageModules.kepler.js +1 -1
- package/build/ExpoImageModules.kepler.js.map +1 -1
- package/build/ImageViewNativeComponent.js +1 -1
- package/build/ImageViewNativeComponent.js.map +1 -1
- package/kepler/AutoLinkInit.cpp +17 -0
- package/kepler/Constants.h +21 -0
- package/kepler/ExpoImage/ExpoImageTurboModule.cpp +148 -0
- package/kepler/ExpoImage/ExpoImageTurboModule.h +41 -0
- package/kepler/ExpoImage/PrefetchListener.cpp +45 -0
- package/kepler/ExpoImage/PrefetchListener.h +40 -0
- package/kepler/ExpoImageComponent/AccessibilityDelegate.cpp +33 -0
- package/kepler/ExpoImageComponent/AccessibilityDelegate.h +30 -0
- package/kepler/ExpoImageComponent/ExpoImageComponentViewManager.cpp +132 -0
- package/kepler/ExpoImageComponent/ExpoImageComponentViewManager.h +66 -0
- package/kepler/ExpoImageComponent/ExpoImageStore.h +102 -0
- package/kepler/ExpoImageComponent/ExpoImageView.cpp +556 -0
- package/kepler/ExpoImageComponent/ExpoImageView.h +186 -0
- package/kepler/ExpoImageComponent/HashImageDecoder.cpp +91 -0
- package/kepler/ExpoImageComponent/HashImageDecoder.h +18 -0
- package/kepler/ExpoImageComponent/ImageLoadListeners.cpp +73 -0
- package/kepler/ExpoImageComponent/ImageLoadListeners.h +52 -0
- package/kepler/ExpoImageComponent/TransitionAnimator.cpp +113 -0
- package/kepler/ExpoImageComponent/TransitionAnimator.h +32 -0
- package/kepler/ImageSourceInfo.h +21 -0
- package/kepler/ViewManagerFactory.cpp +36 -0
- package/kepler/ViewManagerFactory.h +29 -0
- package/kepler/blurhash/common.h +11 -10
- package/kepler/blurhash/decode.cpp +26 -16
- package/kepler/contentposition/ImageContentPosition.cpp +50 -69
- package/kepler/contentposition/ImageContentPosition.h +36 -26
- package/kepler/enums/ImageContentFit.h +47 -15
- package/kepler/enums/ImagePriority.h +12 -13
- package/kepler/test/blurhash/decode.cpp +36 -27
- package/kepler/test/contentposition/ImageContentPosition.cpp +70 -76
- package/kepler/test/thumbhash/decode.cpp +18 -10
- package/kepler/test/utils/Base64.cpp +73 -0
- package/kepler/test/utils/ColorUtils.cpp +53 -0
- package/kepler/test/utils/SourceSelection.cpp +87 -0
- package/kepler/thumbhash/decode.cpp +7 -16
- package/kepler/utils/Base64.cpp +85 -0
- package/kepler/utils/Base64.h +36 -0
- package/kepler/utils/ColorUtils.h +26 -0
- package/kepler/utils/SourceSelection.cpp +80 -0
- package/kepler/utils/SourceSelection.h +65 -0
- package/lib/aarch64-release/com.amazon.kepler.uitoolkit.react.expoimageapp.so +0 -0
- package/lib/aarch64-release/libexpo-image-3.so +0 -0
- package/lib/armv7-release/com.amazon.kepler.uitoolkit.react.expoimageapp.so +0 -0
- package/lib/armv7-release/libexpo-image-3.so +0 -0
- package/lib/x86_64-release/com.amazon.kepler.uitoolkit.react.expoimageapp.so +0 -0
- package/lib/x86_64-release/libexpo-image-3.so +0 -0
- package/package.json +1 -1
- package/react-native.config.js +12 -4
- package/src/ExpoImageModules.kepler.ts +1 -1
- package/src/ImageViewNativeComponent.ts +1 -1
- package/kepler/ExpoImage.cpp +0 -63
- package/kepler/ExpoImage.h +0 -29
- package/kepler/ExpoImageCacheHandler.cpp +0 -15
- package/kepler/ExpoImageCacheHandler.h +0 -28
- package/kepler/ExpoImageComponent.cpp +0 -579
- package/kepler/ExpoImageComponent.h +0 -199
- package/kepler/ImageWrapper/BlurhashImageWrapper.cpp +0 -37
- package/kepler/ImageWrapper/BlurhashImageWrapper.h +0 -23
- package/kepler/ImageWrapper/CacheImageWrapper.cpp +0 -80
- package/kepler/ImageWrapper/CacheImageWrapper.h +0 -41
- package/kepler/ImageWrapper/HashImageWrapper.cpp +0 -21
- package/kepler/ImageWrapper/HashImageWrapper.h +0 -22
- package/kepler/ImageWrapper/ImageWrapper.cpp +0 -24
- package/kepler/ImageWrapper/ImageWrapper.h +0 -33
- package/kepler/ImageWrapper/LocalImageWrapper.cpp +0 -61
- package/kepler/ImageWrapper/LocalImageWrapper.h +0 -30
- package/kepler/ImageWrapper/ThumbhashImageWrapper.cpp +0 -33
- package/kepler/ImageWrapper/ThumbhashImageWrapper.h +0 -20
- package/kepler/KeplerImageViewComponent.h +0 -64
- package/kepler/KeplerInit.cpp +0 -35
- package/kepler/managers/ExpoImageManager.cpp +0 -38
- package/kepler/managers/ExpoImageManager.h +0 -23
- package/kepler/test/ExpoImage.cpp +0 -73
- package/kepler/test/ExpoImageComponent.cpp +0 -304
- package/kepler/test/managers/ExpoImageManager.cpp +0 -39
- package/kepler/test/utils/LoaderDelegate.cpp +0 -130
- package/kepler/utils/PlaceholderImageLoaderDelegate.cpp +0 -26
- package/kepler/utils/PlaceholderImageLoaderDelegate.h +0 -26
- package/kepler/utils/PrefetchImageLoaderDelegate.cpp +0 -55
- package/kepler/utils/PrefetchImageLoaderDelegate.h +0 -35
- package/kepler/utils/SourceImageLoaderDelegate.cpp +0 -47
- package/kepler/utils/SourceImageLoaderDelegate.h +0 -42
- package/kepler/utils/SourceImageLoaderDelegateEmitter.cpp +0 -15
- package/kepler/utils/SourceImageLoaderDelegateEmitter.h +0 -28
- package/kepler-compatibility.json +0 -6
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
#include "ExpoImageComponentViewManager.h"
|
|
2
|
+
|
|
3
|
+
#include <apmf/fn.h>
|
|
4
|
+
#include <apmf/iface/com/amazon/apmf/ISubscription.h>
|
|
5
|
+
#include <apmf/iface/com/amazon/apmf/InvalidArgumentError.h>
|
|
6
|
+
#include <apmf/iface/com/amazon/kepler/uitoolkit/react/IJsObjectBuilder.h>
|
|
7
|
+
#include <apmf/iface/com/amazon/kepler/uitoolkit/view/IImageView3.h>
|
|
8
|
+
#include <apmf/iface/com/amazon/kepler/uitoolkit/view/IView2.h>
|
|
9
|
+
#include <apmf/iface/com/amazon/kepler/uitoolkit/view/IViewLifecycleListener.h>
|
|
10
|
+
#include <apmf/log.h>
|
|
11
|
+
|
|
12
|
+
#include <limits>
|
|
13
|
+
|
|
14
|
+
namespace expoimage {
|
|
15
|
+
|
|
16
|
+
using namespace apmf::log_levels;
|
|
17
|
+
using apmf::iface::com::amazon::kepler::uitoolkit::view::IImageView3;
|
|
18
|
+
using apmf::iface::com::amazon::kepler::uitoolkit::view::IView2;
|
|
19
|
+
|
|
20
|
+
APMF_DEFINE_LOGGER(ExpoImageVMLogger, "com.amazon.kepler.uitoolkit.react.expoimage.vm");
|
|
21
|
+
|
|
22
|
+
ExpoImageComponentViewManager::ExpoImageComponentViewManager(View<IViewModule> viewModule) {
|
|
23
|
+
viewModule_ = viewModule;
|
|
24
|
+
// use the single process-wide store (shared loader +
|
|
25
|
+
// decoded-image cache) so every view manager AND the ExpoImage TurboModule's
|
|
26
|
+
// clearMemoryCache() operate on the same cache. The shared loader is created
|
|
27
|
+
// lazily here on first construction.
|
|
28
|
+
store_ = sharedExpoImageStore();
|
|
29
|
+
if (viewModule_ && !store_->loader) {
|
|
30
|
+
store_->loader = viewModule_->makeImageLoader();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
Ptr<IView> ExpoImageComponentViewManager::createEntry(Ptr<IView> containerPtr) {
|
|
35
|
+
// Hierarchy: containerPtr → clipView (clips descendants) → imageView.
|
|
36
|
+
// clipView is sized to the cell bounds and clips the imageView when it is
|
|
37
|
+
// sized to the image's natural dimensions (Fit::NONE / ScaleDown-small).
|
|
38
|
+
auto clipView = viewModule_->makeView();
|
|
39
|
+
if (!clipView) {
|
|
40
|
+
throw apmf::InvalidArgumentError("ExpoImage: viewModule->makeView() returned null for clipView");
|
|
41
|
+
}
|
|
42
|
+
auto clipView2 = clipView.TryQueryInterface<IView2>();
|
|
43
|
+
if (clipView2) clipView2->setContentClipping(true);
|
|
44
|
+
|
|
45
|
+
auto imageViewBase = viewModule_->makeImageView();
|
|
46
|
+
if (!imageViewBase) {
|
|
47
|
+
throw apmf::InvalidArgumentError("ExpoImage: viewModule->makeImageView() returned null");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
auto imageView = imageViewBase.TryQueryInterface<IImageView3>();
|
|
51
|
+
if (!imageView) {
|
|
52
|
+
throw apmf::InvalidArgumentError("ExpoImage: IImageView3 query returned null");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
clipView->addChild(imageViewBase);
|
|
56
|
+
containerPtr->addChild(clipView);
|
|
57
|
+
|
|
58
|
+
void* key = containerPtr.get();
|
|
59
|
+
views_[key] = std::make_unique<ExpoImageView>(viewModule_, containerPtr, clipView, imageView, store_);
|
|
60
|
+
|
|
61
|
+
// erase the per-view entry when the IView detaches.
|
|
62
|
+
//
|
|
63
|
+
// The log proved cells are genuinely RECREATED on every navigation step
|
|
64
|
+
// (createEntry fires per step; liveEntries climbs monotonically), so an
|
|
65
|
+
// earlier "never erase" experiment leaked an ExpoImageView (+ detached
|
|
66
|
+
// clip/image render objects) per step (102 -> 196+ and growing). Erasing is
|
|
67
|
+
// now both correct AND flicker-free, because the decoded image is persisted
|
|
68
|
+
// by the shared ExpoImageStore cache (not by the view) -- a recreated cell
|
|
69
|
+
// re-paints synchronously from the cache in loadSource(). An in-flight load
|
|
70
|
+
// also survives this erase: it runs on the shared loader and its listener
|
|
71
|
+
// owns the captures, so it still completes and warms the cache.
|
|
72
|
+
auto sub = containerPtr->addLifecycleListener(apmf::Fn(
|
|
73
|
+
[](apmf::method::onMount, View<IView>) {},
|
|
74
|
+
[this, key](apmf::method::onUnmount, View<IView>) {
|
|
75
|
+
auto it = views_.find(key);
|
|
76
|
+
if (it == views_.end()) return;
|
|
77
|
+
// Move the entry out first so ~ExpoImageView runs only AFTER the
|
|
78
|
+
// map is consistent and this callback has returned.
|
|
79
|
+
auto doomed = std::move(it->second);
|
|
80
|
+
views_.erase(it);
|
|
81
|
+
}));
|
|
82
|
+
views_[key]->lifecycleSub_ = std::move(sub);
|
|
83
|
+
return containerPtr;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
Ptr<IView> ExpoImageComponentViewManager::makeView() {
|
|
87
|
+
return createEntry(viewModule_->makeView());
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
ExpoImageView& ExpoImageComponentViewManager::ensureEntry(View<IView> view) {
|
|
91
|
+
void* key = view.get();
|
|
92
|
+
auto it = views_.find(key);
|
|
93
|
+
if (it == views_.end()) {
|
|
94
|
+
createEntry(Ptr<IView>(view));
|
|
95
|
+
it = views_.find(key);
|
|
96
|
+
}
|
|
97
|
+
return *it->second;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
Ptr<IPropsRegistry> ExpoImageComponentViewManager::registerProps(View<IPropsRegistryBuilder> builder) {
|
|
101
|
+
auto emptyObj = context_->makeJsObjectBuilder()->build();
|
|
102
|
+
builder->stringPropWithDefault("contentFit", "cover");
|
|
103
|
+
builder->stringPropWithDefault("placeholderContentFit", "scale-down");
|
|
104
|
+
builder->boolPropWithDefault("allowDownscaling", true);
|
|
105
|
+
builder->objectPropWithDefault("contentPosition", emptyObj);
|
|
106
|
+
builder->intPropWithDefault("tintColor", std::numeric_limits<int>::max());
|
|
107
|
+
builder->intPropWithDefault("overlayColor", std::numeric_limits<int>::max());
|
|
108
|
+
builder->doublePropWithDefault("blurRadius", 0.0);
|
|
109
|
+
builder->arrayProp("placeholder");
|
|
110
|
+
builder->arrayProp("source");
|
|
111
|
+
builder->stringPropWithDefault("priority", "normal");
|
|
112
|
+
builder->objectPropWithDefault("transition", emptyObj);
|
|
113
|
+
builder->stringPropWithDefault("recyclingKey", "");
|
|
114
|
+
builder->stringPropWithDefault("accessibilityLabel", "");
|
|
115
|
+
builder->stringPropWithDefault("alt", "");
|
|
116
|
+
builder->boolPropWithDefault("accessible", true);
|
|
117
|
+
return builder->build();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
void ExpoImageComponentViewManager::updateContext(View<IContext> context) {
|
|
121
|
+
context_ = context;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
void ExpoImageComponentViewManager::updateProps(View<IView> view, View<IJsObject> newProps) {
|
|
125
|
+
ensureEntry(view).updateProps(newProps, context_);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
void ExpoImageComponentViewManager::updateLayout(View<IView> view, View<ILayout> newLayout) {
|
|
129
|
+
ensureEntry(view).updateLayout(newLayout);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
} // namespace expoimage
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <apmf/apmf_base.h>
|
|
4
|
+
#include <apmf/iface/com/amazon/kepler/uitoolkit/react/IContext.h>
|
|
5
|
+
#include <apmf/iface/com/amazon/kepler/uitoolkit/react/IContextDelegate.h>
|
|
6
|
+
#include <apmf/iface/com/amazon/kepler/uitoolkit/react/IJsObject.h>
|
|
7
|
+
#include <apmf/iface/com/amazon/kepler/uitoolkit/react/ILayout.h>
|
|
8
|
+
#include <apmf/iface/com/amazon/kepler/uitoolkit/react/ILayoutDelegate.h>
|
|
9
|
+
#include <apmf/iface/com/amazon/kepler/uitoolkit/react/IPropsDelegate.h>
|
|
10
|
+
#include <apmf/iface/com/amazon/kepler/uitoolkit/react/IPropsRegistry.h>
|
|
11
|
+
#include <apmf/iface/com/amazon/kepler/uitoolkit/react/IPropsRegistryBuilder.h>
|
|
12
|
+
#include <apmf/iface/com/amazon/kepler/uitoolkit/react/IViewManager.h>
|
|
13
|
+
#include <apmf/iface/com/amazon/kepler/uitoolkit/view/IView.h>
|
|
14
|
+
#include <apmf/iface/com/amazon/kepler/uitoolkit/view/IViewModule.h>
|
|
15
|
+
#include <apmf/ptr.h>
|
|
16
|
+
|
|
17
|
+
#include "ExpoImageView.h"
|
|
18
|
+
|
|
19
|
+
#include <memory>
|
|
20
|
+
#include <unordered_map>
|
|
21
|
+
|
|
22
|
+
namespace expoimage {
|
|
23
|
+
|
|
24
|
+
using apmf::ApmfBase;
|
|
25
|
+
using apmf::Ptr;
|
|
26
|
+
using apmf::View;
|
|
27
|
+
using apmf::iface::com::amazon::kepler::uitoolkit::react::IContext;
|
|
28
|
+
using apmf::iface::com::amazon::kepler::uitoolkit::react::IContextDelegate;
|
|
29
|
+
using apmf::iface::com::amazon::kepler::uitoolkit::react::IJsObject;
|
|
30
|
+
using apmf::iface::com::amazon::kepler::uitoolkit::react::ILayout;
|
|
31
|
+
using apmf::iface::com::amazon::kepler::uitoolkit::react::ILayoutDelegate;
|
|
32
|
+
using apmf::iface::com::amazon::kepler::uitoolkit::react::IPropsDelegate;
|
|
33
|
+
using apmf::iface::com::amazon::kepler::uitoolkit::react::IPropsRegistry;
|
|
34
|
+
using apmf::iface::com::amazon::kepler::uitoolkit::react::IPropsRegistryBuilder;
|
|
35
|
+
using apmf::iface::com::amazon::kepler::uitoolkit::react::IViewManager;
|
|
36
|
+
using apmf::iface::com::amazon::kepler::uitoolkit::view::IView;
|
|
37
|
+
using apmf::iface::com::amazon::kepler::uitoolkit::view::IViewModule;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Singleton ViewManager — thin dispatcher that delegates to per-view ExpoImageView instances.
|
|
41
|
+
*/
|
|
42
|
+
struct ExpoImageComponentViewManager
|
|
43
|
+
: ApmfBase<ExpoImageComponentViewManager, IViewManager, IContextDelegate, IPropsDelegate, ILayoutDelegate> {
|
|
44
|
+
public:
|
|
45
|
+
explicit ExpoImageComponentViewManager(View<IViewModule> viewModule);
|
|
46
|
+
|
|
47
|
+
Ptr<IView> makeView();
|
|
48
|
+
Ptr<IPropsRegistry> registerProps(View<IPropsRegistryBuilder> builder);
|
|
49
|
+
void updateContext(View<IContext> context);
|
|
50
|
+
void updateProps(View<IView> view, View<IJsObject> newProps);
|
|
51
|
+
void updateLayout(View<IView> view, View<ILayout> newLayout);
|
|
52
|
+
|
|
53
|
+
private:
|
|
54
|
+
ExpoImageView& ensureEntry(View<IView> view);
|
|
55
|
+
Ptr<IView> createEntry(Ptr<IView> containerPtr);
|
|
56
|
+
|
|
57
|
+
Ptr<IViewModule> viewModule_;
|
|
58
|
+
Ptr<IContext> context_;
|
|
59
|
+
std::unordered_map<void*, std::unique_ptr<ExpoImageView>> views_;
|
|
60
|
+
// shared loader + decoded-image cache, lives for the whole
|
|
61
|
+
// process (this view manager is a singleton). Shared by every ExpoImageView so
|
|
62
|
+
// loads survive cell recreation and repeat posters paint synchronously.
|
|
63
|
+
std::shared_ptr<ExpoImageStore> store_;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
} // namespace expoimage
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
*
|
|
4
|
+
* PROPRIETARY/CONFIDENTIAL
|
|
5
|
+
* Use is subject to license terms.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#include <apmf/iface/com/amazon/kepler/uitoolkit/view/IImage.h>
|
|
11
|
+
#include <apmf/iface/com/amazon/kepler/uitoolkit/view/IImageLoader.h>
|
|
12
|
+
#include <apmf/ptr.h>
|
|
13
|
+
|
|
14
|
+
#include <list>
|
|
15
|
+
#include <memory>
|
|
16
|
+
#include <string>
|
|
17
|
+
#include <unordered_map>
|
|
18
|
+
|
|
19
|
+
namespace expoimage {
|
|
20
|
+
|
|
21
|
+
using apmf::Ptr;
|
|
22
|
+
namespace vi = apmf::iface::com::amazon::kepler::uitoolkit::view;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* process-wide store shared by ALL expo-image cells, owned as a
|
|
26
|
+
* single process-wide instance (sharedExpoImageStore()). Two responsibilities:
|
|
27
|
+
* - `loader`: a SINGLE IImageLoader shared by every cell. Because it outlives any
|
|
28
|
+
* individual cell, an in-flight load is NOT canceled when a fast-navigated
|
|
29
|
+
* recycling row tears the cell down -- the load completes and populates the
|
|
30
|
+
* cache for next time.
|
|
31
|
+
* - the cache: a bounded key -> decoded IImage map. A (re)created cell whose key
|
|
32
|
+
* is already cached paints SYNCHRONOUSLY (setImage same frame) with no async
|
|
33
|
+
* round-trip, mirroring the pre-migration cached behaviour.
|
|
34
|
+
*
|
|
35
|
+
* Threading: every member is touched only on the UI thread. The stable
|
|
36
|
+
* IImageLoader posts its onSuccess/onFailure callbacks back to the UI RunLoop
|
|
37
|
+
* (download/decode happen on worker threads, completion is dispatched to the UI
|
|
38
|
+
* thread), so get()/put()/clear() and the cell prop/layout updates all run on the
|
|
39
|
+
* same thread -- no synchronization is required. clearMemoryCache() schedules
|
|
40
|
+
* clear() onto the UI RunLoop for the same reason.
|
|
41
|
+
*/
|
|
42
|
+
struct ExpoImageStore {
|
|
43
|
+
Ptr<vi::IImageLoader> loader;
|
|
44
|
+
|
|
45
|
+
// Sized to comfortably hold a full row's worth of posters (plus a margin) so a
|
|
46
|
+
// second pass through a list stays fully cached with no eviction re-flicker.
|
|
47
|
+
// Decoded images are view-sized (see computePreferredSize), so each entry is
|
|
48
|
+
// small.
|
|
49
|
+
size_t maxEntries{128};
|
|
50
|
+
|
|
51
|
+
// Returns the cached image for `key`, promoting it to most-recently-used.
|
|
52
|
+
Ptr<vi::IImage> get(const std::string& key) {
|
|
53
|
+
auto it = cache_.find(key);
|
|
54
|
+
if (it == cache_.end()) {
|
|
55
|
+
return Ptr<vi::IImage>{};
|
|
56
|
+
}
|
|
57
|
+
lru_.splice(lru_.end(), lru_, it->second.lruIt); // promote to MRU
|
|
58
|
+
return it->second.img;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Inserts/updates `key`, evicting the least-recently-used entry at capacity.
|
|
62
|
+
void put(const std::string& key, Ptr<vi::IImage> img) {
|
|
63
|
+
if (key.empty() || !img) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
auto it = cache_.find(key);
|
|
67
|
+
if (it != cache_.end()) {
|
|
68
|
+
it->second.img = img;
|
|
69
|
+
lru_.splice(lru_.end(), lru_, it->second.lruIt); // promote to MRU
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
while (cache_.size() >= maxEntries && !lru_.empty()) {
|
|
73
|
+
cache_.erase(lru_.front());
|
|
74
|
+
lru_.pop_front();
|
|
75
|
+
}
|
|
76
|
+
lru_.push_back(key);
|
|
77
|
+
cache_.emplace(key, Entry{img, std::prev(lru_.end())});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Drops all cached decoded images (memory cache). The shared loader is kept.
|
|
81
|
+
void clear() {
|
|
82
|
+
cache_.clear();
|
|
83
|
+
lru_.clear();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
private:
|
|
87
|
+
struct Entry {
|
|
88
|
+
Ptr<vi::IImage> img;
|
|
89
|
+
std::list<std::string>::iterator lruIt;
|
|
90
|
+
};
|
|
91
|
+
std::list<std::string> lru_; // front = LRU, back = MRU
|
|
92
|
+
std::unordered_map<std::string, Entry> cache_;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// Single process-wide store, shared by every ExpoImageComponentViewManager and by
|
|
96
|
+
// the ExpoImage TurboModule (so JS clearMemoryCache() can release it).
|
|
97
|
+
inline std::shared_ptr<ExpoImageStore> sharedExpoImageStore() {
|
|
98
|
+
static std::shared_ptr<ExpoImageStore> instance = std::make_shared<ExpoImageStore>();
|
|
99
|
+
return instance;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
} // namespace expoimage
|