@shopify/react-native-skia 2.13.0 → 2.13.1
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/android/cpp/rnskia-android/OpenGLContext.h +1 -1
- package/android/cpp/rnskia-android/gl/Surface.h +1 -1
- package/cpp/api/JsiSkImage.h +1 -1
- package/cpp/api/JsiSkImageFilter.h +3 -1
- package/cpp/api/JsiSkParagraph.h +2 -1
- package/cpp/api/JsiSkParagraphBuilder.h +1 -1
- package/cpp/api/JsiSkParagraphBuilderFactory.h +1 -1
- package/cpp/api/JsiSkPath.h +11 -4
- package/cpp/api/JsiSkPathBuilder.h +11 -4
- package/cpp/api/JsiSkPictureRecorder.h +2 -1
- package/cpp/api/JsiSkShader.h +3 -1
- package/cpp/api/JsiSkSkottie.h +27 -25
- package/cpp/api/recorder/Command.h +1 -1
- package/cpp/api/recorder/Convertor.h +1 -1
- package/cpp/api/recorder/DataTypes.h +1 -1
- package/cpp/api/recorder/DrawingCtx.h +1 -1
- package/cpp/api/recorder/JsiRecorder.h +7 -4
- package/cpp/api/third_party/base64.cpp +1 -1
- package/cpp/jsi/JSICache.cpp +23 -0
- package/cpp/jsi/JSICache.h +28 -1
- package/cpp/jsi/NativeObject.h +36 -7
- package/cpp/rnskia/RNDawnContext.h +1 -1
- package/lib/commonjs/animation/functions/interpolatePaths.js +18 -0
- package/lib/commonjs/animation/functions/interpolatePaths.js.map +1 -1
- package/lib/module/animation/functions/interpolatePaths.js +18 -0
- package/lib/module/animation/functions/interpolatePaths.js.map +1 -1
- package/package.json +1 -1
- package/src/animation/functions/interpolatePaths.ts +24 -0
|
@@ -28,7 +28,7 @@ public:
|
|
|
28
28
|
|
|
29
29
|
gl::Display *getDisplay() { return _glDisplay.get(); }
|
|
30
30
|
gl::Context *getContext() { return _glContext.get(); }
|
|
31
|
-
gl::Surface *getSurface() { return _glSurface.get(); }
|
|
31
|
+
gl::Surface *getSurface() { return _glSurface.get(); }
|
|
32
32
|
EGLConfig getConfig() { return _glConfig; }
|
|
33
33
|
|
|
34
34
|
private:
|
package/cpp/api/JsiSkImage.h
CHANGED
|
@@ -66,7 +66,7 @@ static sk_sp<SkData> replaceJpegICCWithAppleP3(sk_sp<SkData> jpegData) {
|
|
|
66
66
|
return jpegData;
|
|
67
67
|
|
|
68
68
|
const uint8_t *iccBytes = CFDataGetBytePtr(cfICC);
|
|
69
|
-
size_t iccLen = (
|
|
69
|
+
size_t iccLen = static_cast<size_t>(CFDataGetLength(cfICC));
|
|
70
70
|
|
|
71
71
|
// "ICC_PROFILE\0" APP2 marker signature (12 bytes)
|
|
72
72
|
static const uint8_t iccSig[] = {0x49, 0x43, 0x43, 0x5F, 0x50, 0x52,
|
|
@@ -28,7 +28,9 @@ public:
|
|
|
28
28
|
: JsiSkWrappingSkPtrNativeObject<JsiSkImageFilter, SkImageFilter>(
|
|
29
29
|
std::move(context), std::move(imageFilter)) {}
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
// A image filter node is a few hundred bytes; the images it may reference
|
|
32
|
+
// are reported by their own wrappers.
|
|
33
|
+
size_t getMemoryPressure() override { return kMinMemoryPressure; }
|
|
32
34
|
|
|
33
35
|
static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) {
|
|
34
36
|
installCommon(runtime, prototype);
|
package/cpp/api/JsiSkParagraph.h
CHANGED
|
@@ -277,7 +277,8 @@ public:
|
|
|
277
277
|
&JsiSkParagraph::extendedVisit);
|
|
278
278
|
}
|
|
279
279
|
|
|
280
|
-
|
|
280
|
+
// Shaped glyph runs and line metrics; there is no exact API for this.
|
|
281
|
+
size_t getMemoryPressure() override { return 16 * 1024; }
|
|
281
282
|
|
|
282
283
|
explicit JsiSkParagraph(std::shared_ptr<RNSkPlatformContext> context,
|
|
283
284
|
para::ParagraphBuilder *paragraphBuilder)
|
|
@@ -93,7 +93,7 @@ public:
|
|
|
93
93
|
&JsiSkParagraphBuilder::pop);
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
size_t getMemoryPressure() override { return
|
|
96
|
+
size_t getMemoryPressure() override { return kMinMemoryPressure; }
|
|
97
97
|
|
|
98
98
|
explicit JsiSkParagraphBuilder(std::shared_ptr<RNSkPlatformContext> context,
|
|
99
99
|
para::ParagraphStyle paragraphStyle,
|
|
@@ -47,7 +47,7 @@ public:
|
|
|
47
47
|
&JsiSkParagraphBuilderFactory::Make);
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
size_t getMemoryPressure() override { return
|
|
50
|
+
size_t getMemoryPressure() override { return kMinMemoryPressure; }
|
|
51
51
|
|
|
52
52
|
explicit JsiSkParagraphBuilderFactory(
|
|
53
53
|
std::shared_ptr<RNSkPlatformContext> context)
|
package/cpp/api/JsiSkPath.h
CHANGED
|
@@ -640,11 +640,18 @@ public:
|
|
|
640
640
|
: JsiSkPath(std::move(context), SkPathBuilder(path)) {}
|
|
641
641
|
|
|
642
642
|
size_t getMemoryPressure() override {
|
|
643
|
-
|
|
644
|
-
if (!builder)
|
|
643
|
+
if (isDisposed()) {
|
|
645
644
|
return 0;
|
|
646
|
-
|
|
647
|
-
|
|
645
|
+
}
|
|
646
|
+
auto builder = getObjectUnchecked();
|
|
647
|
+
if (!builder) {
|
|
648
|
+
return 0;
|
|
649
|
+
}
|
|
650
|
+
// The point, verb and conic weight arrays of the builder. Snapshotting
|
|
651
|
+
// the path to measure it would copy them, and this runs on every round
|
|
652
|
+
// trip of the object to JS.
|
|
653
|
+
return builder->points().size_bytes() + builder->verbs().size_bytes() +
|
|
654
|
+
builder->conicWeights().size_bytes();
|
|
648
655
|
}
|
|
649
656
|
|
|
650
657
|
/**
|
|
@@ -271,11 +271,18 @@ public:
|
|
|
271
271
|
std::make_shared<SkPathBuilder>(std::move(builder))) {}
|
|
272
272
|
|
|
273
273
|
size_t getMemoryPressure() override {
|
|
274
|
-
|
|
275
|
-
if (!builder)
|
|
274
|
+
if (isDisposed()) {
|
|
276
275
|
return 0;
|
|
277
|
-
|
|
278
|
-
|
|
276
|
+
}
|
|
277
|
+
auto builder = getObjectUnchecked();
|
|
278
|
+
if (!builder) {
|
|
279
|
+
return 0;
|
|
280
|
+
}
|
|
281
|
+
// The point, verb and conic weight arrays of the builder. Snapshotting
|
|
282
|
+
// the path to measure it would copy them, and this runs on every round
|
|
283
|
+
// trip of the object to JS.
|
|
284
|
+
return builder->points().size_bytes() + builder->verbs().size_bytes() +
|
|
285
|
+
builder->conicWeights().size_bytes();
|
|
279
286
|
}
|
|
280
287
|
|
|
281
288
|
static jsi::Value toValue(jsi::Runtime &runtime,
|
|
@@ -58,7 +58,8 @@ public:
|
|
|
58
58
|
&JsiSkPictureRecorder::finishRecordingAsPicture);
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
|
|
61
|
+
// The recorded picture reports its own size once finished.
|
|
62
|
+
size_t getMemoryPressure() override { return kMinMemoryPressure; }
|
|
62
63
|
|
|
63
64
|
static const jsi::HostFunctionType
|
|
64
65
|
createCtor(std::shared_ptr<RNSkPlatformContext> context) {
|
package/cpp/api/JsiSkShader.h
CHANGED
|
@@ -29,7 +29,9 @@ public:
|
|
|
29
29
|
: JsiSkWrappingSkPtrNativeObject<JsiSkShader, SkShader>(
|
|
30
30
|
std::move(context), std::move(shader)) {}
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
// A shader node is a few hundred bytes; the images it may reference
|
|
33
|
+
// are reported by their own wrappers.
|
|
34
|
+
size_t getMemoryPressure() override { return kMinMemoryPressure; }
|
|
33
35
|
|
|
34
36
|
static sk_sp<SkShader> fromValue(jsi::Runtime &runtime,
|
|
35
37
|
const jsi::Value &obj) {
|
package/cpp/api/JsiSkSkottie.h
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
|
+
#include <algorithm>
|
|
3
4
|
#include <memory>
|
|
4
5
|
#include <optional>
|
|
5
6
|
#include <string>
|
|
@@ -31,7 +32,7 @@
|
|
|
31
32
|
#pragma clang diagnostic pop
|
|
32
33
|
|
|
33
34
|
namespace RNSkia {
|
|
34
|
-
|
|
35
|
+
namespace jsi = facebook::jsi;
|
|
35
36
|
|
|
36
37
|
std::unique_ptr<SkCodec> DecodeImageData(sk_sp<SkData> data) {
|
|
37
38
|
if (data == nullptr) {
|
|
@@ -74,6 +75,8 @@ public:
|
|
|
74
75
|
if (!codec) {
|
|
75
76
|
return nullptr;
|
|
76
77
|
}
|
|
78
|
+
// The asset keeps its decoded frame for the lifetime of the animation.
|
|
79
|
+
_decodedImageBytes += codec->getInfo().computeMinByteSize();
|
|
77
80
|
return skresources::MultiFrameImageAsset::Make(std::move(codec));
|
|
78
81
|
}
|
|
79
82
|
|
|
@@ -102,11 +105,16 @@ public:
|
|
|
102
105
|
return this->findAsset(name);
|
|
103
106
|
}
|
|
104
107
|
|
|
108
|
+
// Bytes of the decoded images for the assets loaded so far.
|
|
109
|
+
size_t decodedImageBytes() const { return _decodedImageBytes; }
|
|
110
|
+
|
|
105
111
|
private:
|
|
106
112
|
explicit SkottieAssetProvider(AssetMap assets, sk_sp<SkFontMgr> fontMgr)
|
|
107
113
|
: fAssets(std::move(assets)), fFontMgr(std::move(fontMgr)) {}
|
|
108
114
|
const AssetMap fAssets;
|
|
109
115
|
const sk_sp<SkFontMgr> fFontMgr;
|
|
116
|
+
// loadImageAsset() is const in skottie::ResourceProvider.
|
|
117
|
+
mutable size_t _decodedImageBytes = 0;
|
|
110
118
|
|
|
111
119
|
sk_sp<SkData> findAsset(const char name[]) const {
|
|
112
120
|
auto it = fAssets.find(name);
|
|
@@ -121,6 +129,12 @@ class ManagedAnimation {
|
|
|
121
129
|
public:
|
|
122
130
|
ManagedAnimation(std::string json, SkottieAssetProvider::AssetMap assets,
|
|
123
131
|
sk_sp<SkFontMgr> fontMgr) {
|
|
132
|
+
_approximateBytesUsed = json.size();
|
|
133
|
+
for (const auto &asset : assets) {
|
|
134
|
+
if (asset.second) {
|
|
135
|
+
_approximateBytesUsed += asset.second->size();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
124
138
|
_propManager = std::make_unique<CustomPropertyManager>(
|
|
125
139
|
CustomPropertyManager::Mode::kCollapseProperties, "");
|
|
126
140
|
_resourceProvider =
|
|
@@ -132,6 +146,8 @@ public:
|
|
|
132
146
|
builder->setPropertyObserver(_propManager->getPropertyObserver());
|
|
133
147
|
_animation = builder->make(json.c_str(), json.size());
|
|
134
148
|
_slotManager = builder->getSlotManager();
|
|
149
|
+
// Image assets are loaded while the animation is built.
|
|
150
|
+
_approximateBytesUsed += _resourceProvider->decodedImageBytes();
|
|
135
151
|
}
|
|
136
152
|
|
|
137
153
|
~ManagedAnimation() {
|
|
@@ -151,6 +167,10 @@ public:
|
|
|
151
167
|
sk_sp<skottie::SlotManager> _slotManager = nullptr;
|
|
152
168
|
sk_sp<SkottieAssetProvider> _resourceProvider = nullptr;
|
|
153
169
|
std::unique_ptr<CustomPropertyManager> _propManager = nullptr;
|
|
170
|
+
// Size of the animation JSON, its encoded assets and its decoded images:
|
|
171
|
+
// the memory the animation actually owns (the scene graph is in the same
|
|
172
|
+
// order as the JSON). Used as the GC hint for the wrapper.
|
|
173
|
+
size_t _approximateBytesUsed = 0;
|
|
154
174
|
};
|
|
155
175
|
|
|
156
176
|
class JsiSkSkottie
|
|
@@ -579,31 +599,13 @@ public:
|
|
|
579
599
|
|
|
580
600
|
size_t getMemoryPressure() override {
|
|
581
601
|
auto animation = getObject();
|
|
582
|
-
if (!animation
|
|
583
|
-
return
|
|
602
|
+
if (!animation) {
|
|
603
|
+
return kMinMemoryPressure;
|
|
584
604
|
}
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
// Estimate memory usage based on animation properties
|
|
591
|
-
// Base calculation: width * height * 4 bytes per pixel * estimated frame
|
|
592
|
-
// count
|
|
593
|
-
size_t frameCount = static_cast<size_t>(duration * fps);
|
|
594
|
-
size_t estimatedFrameSize =
|
|
595
|
-
static_cast<size_t>(size.width() * size.height() * 4);
|
|
596
|
-
|
|
597
|
-
// Conservative estimate: assume some frames are cached
|
|
598
|
-
size_t cachedFrames =
|
|
599
|
-
std::min(frameCount, static_cast<size_t>(60)); // Max 60 cached frames
|
|
600
|
-
size_t animationMemory = estimatedFrameSize * cachedFrames;
|
|
601
|
-
|
|
602
|
-
// Add base overhead for animation data structures
|
|
603
|
-
size_t baseOverhead =
|
|
604
|
-
64 * 1024; // 64KB for metadata, property managers, etc.
|
|
605
|
-
|
|
606
|
-
return animationMemory + baseOverhead;
|
|
605
|
+
// Skottie keeps no frame cache: report the bytes the animation owns.
|
|
606
|
+
// Estimating a pixel cache here (width * height * 4 * 60 frames) charged
|
|
607
|
+
// hundreds of MB per wrapper, and each capture in a worklet repeated it.
|
|
608
|
+
return std::max(animation->_approximateBytesUsed, kMinMemoryPressure);
|
|
607
609
|
}
|
|
608
610
|
};
|
|
609
611
|
} // namespace RNSkia
|
|
@@ -692,7 +692,7 @@ SkPath1DPathEffect::Style getPropertyValue(jsi::Runtime &runtime,
|
|
|
692
692
|
// specialization
|
|
693
693
|
struct BlendModeValue {
|
|
694
694
|
int value;
|
|
695
|
-
BlendModeValue(int v = 0) : value(v) {}
|
|
695
|
+
explicit BlendModeValue(int v = 0) : value(v) {}
|
|
696
696
|
operator int() const { return value; }
|
|
697
697
|
};
|
|
698
698
|
|
|
@@ -24,7 +24,7 @@ class JsiRecorder
|
|
|
24
24
|
public:
|
|
25
25
|
static constexpr const char *CLASS_NAME = "Recorder";
|
|
26
26
|
|
|
27
|
-
JsiRecorder(std::shared_ptr<RNSkPlatformContext> context)
|
|
27
|
+
explicit JsiRecorder(std::shared_ptr<RNSkPlatformContext> context)
|
|
28
28
|
: JsiSkWrappingSharedPtrNativeObject<JsiRecorder, Recorder>(
|
|
29
29
|
std::move(context), std::make_shared<Recorder>()) {
|
|
30
30
|
getObject()->_context = getContext();
|
|
@@ -379,9 +379,12 @@ public:
|
|
|
379
379
|
installHostMethod(runtime, prototype, "reset", &JsiRecorder::reset);
|
|
380
380
|
}
|
|
381
381
|
|
|
382
|
-
//
|
|
383
|
-
//
|
|
384
|
-
|
|
382
|
+
// The recorder itself is a small command list. The resources it references
|
|
383
|
+
// (images, pictures, paths) report their own size through their wrappers
|
|
384
|
+
// and the pictures produced by play() report theirs. Do not put a made-up
|
|
385
|
+
// number here: a new recorder is created on every React commit and the
|
|
386
|
+
// charge is repeated each time it is unboxed on the UI runtime.
|
|
387
|
+
size_t getMemoryPressure() override { return kMinMemoryPressure; }
|
|
385
388
|
|
|
386
389
|
static const jsi::HostFunctionType
|
|
387
390
|
createCtor(std::shared_ptr<RNSkPlatformContext> context) {
|
package/cpp/jsi/JSICache.cpp
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#include "JSICache.h"
|
|
2
2
|
|
|
3
|
+
#include <algorithm>
|
|
3
4
|
#include <iterator>
|
|
4
5
|
#include <memory>
|
|
5
6
|
#include <stdexcept>
|
|
@@ -96,4 +97,26 @@ jsi::Object &JSICache::setPrototype(PrototypeKey key, jsi::Object prototype) {
|
|
|
96
97
|
return it->second;
|
|
97
98
|
}
|
|
98
99
|
|
|
100
|
+
jsi::Value JSICache::lockWrapper(jsi::Runtime &runtime,
|
|
101
|
+
const void *nativeObject) {
|
|
102
|
+
auto it = _wrappers.find(nativeObject);
|
|
103
|
+
if (it == _wrappers.end()) {
|
|
104
|
+
return jsi::Value::undefined();
|
|
105
|
+
}
|
|
106
|
+
return it->second.lock(runtime);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
void JSICache::setWrapper(jsi::Runtime &runtime, const void *nativeObject,
|
|
110
|
+
const jsi::Object &wrapper) {
|
|
111
|
+
_wrappers.insert_or_assign(nativeObject, jsi::WeakObject(runtime, wrapper));
|
|
112
|
+
if (_wrappers.size() < _pruneWrappersAt) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
for (auto it = _wrappers.begin(); it != _wrappers.end();) {
|
|
116
|
+
it = it->second.lock(runtime).isUndefined() ? _wrappers.erase(it)
|
|
117
|
+
: std::next(it);
|
|
118
|
+
}
|
|
119
|
+
_pruneWrappersAt = std::max(kMinPruneWrappersAt, _wrappers.size() * 2);
|
|
120
|
+
}
|
|
121
|
+
|
|
99
122
|
} // namespace RNJsi
|
package/cpp/jsi/JSICache.h
CHANGED
|
@@ -13,7 +13,8 @@ namespace jsi = facebook::jsi;
|
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Per-runtime store for JSI values that native code wants to keep across
|
|
16
|
-
* calls
|
|
16
|
+
* calls: the prototype object of every NativeObject class, and the JS
|
|
17
|
+
* wrapper of every native object that has one on the runtime.
|
|
17
18
|
*
|
|
18
19
|
* Ownership model (borrowed from react-native-nitro-modules' JSICache):
|
|
19
20
|
*
|
|
@@ -72,6 +73,26 @@ public:
|
|
|
72
73
|
*/
|
|
73
74
|
jsi::Object &setPrototype(PrototypeKey key, jsi::Object prototype);
|
|
74
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Returns the JS wrapper stored for `nativeObject` on this runtime, or
|
|
78
|
+
* undefined if none was stored or the wrapper has been collected.
|
|
79
|
+
*
|
|
80
|
+
* The key is the native object's address. A live wrapper keeps its native
|
|
81
|
+
* object alive (the object is the wrapper's NativeState), so as long as
|
|
82
|
+
* the entry locks it still belongs to that object. Once the wrapper has
|
|
83
|
+
* been collected the entry is stale and is skipped or replaced, so an
|
|
84
|
+
* address reused by a new object can never resolve to the old wrapper.
|
|
85
|
+
*/
|
|
86
|
+
jsi::Value lockWrapper(jsi::Runtime &runtime, const void *nativeObject);
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Stores `wrapper` as the JS wrapper of `nativeObject` on this runtime.
|
|
90
|
+
* Only a weak reference is kept: the wrapper stays collectable, and the
|
|
91
|
+
* native object is released when it goes away.
|
|
92
|
+
*/
|
|
93
|
+
void setWrapper(jsi::Runtime &runtime, const void *nativeObject,
|
|
94
|
+
const jsi::Object &wrapper);
|
|
95
|
+
|
|
75
96
|
JSICache() = default;
|
|
76
97
|
~JSICache() override = default;
|
|
77
98
|
JSICache(const JSICache &) = delete;
|
|
@@ -81,6 +102,12 @@ private:
|
|
|
81
102
|
static std::shared_ptr<JSICache> getOrCreateOnGlobal(jsi::Runtime &runtime);
|
|
82
103
|
|
|
83
104
|
std::unordered_map<PrototypeKey, jsi::Object> _prototypes;
|
|
105
|
+
// Native object -> its wrapper on this runtime. Entries of collected
|
|
106
|
+
// wrappers are pruned in setWrapper once the map has doubled since the
|
|
107
|
+
// last pruning, so it stays proportional to the number of live wrappers.
|
|
108
|
+
std::unordered_map<const void *, jsi::WeakObject> _wrappers;
|
|
109
|
+
size_t _pruneWrappersAt = kMinPruneWrappersAt;
|
|
110
|
+
static constexpr size_t kMinPruneWrappersAt = 64;
|
|
84
111
|
|
|
85
112
|
// Runtime -> cache. Weak on purpose: the runtime's global owns the cache.
|
|
86
113
|
static std::mutex _registryMutex;
|
package/cpp/jsi/NativeObject.h
CHANGED
|
@@ -210,12 +210,12 @@ public:
|
|
|
210
210
|
if (instance == nullptr) {
|
|
211
211
|
throw jsi::JSError(rt, "Invalid boxed native object state");
|
|
212
212
|
}
|
|
213
|
-
// Unboxing
|
|
214
|
-
// Keep the runtime the object was
|
|
215
|
-
// native code (e.g. GPUDevice
|
|
216
|
-
// the creation runtime, and
|
|
217
|
-
//
|
|
218
|
-
// and thread.
|
|
213
|
+
// Unboxing hands back the wrapper cached for the target runtime,
|
|
214
|
+
// creating it on first use. Keep the runtime the object was
|
|
215
|
+
// originally created on: async native code (e.g. GPUDevice
|
|
216
|
+
// error/lost events) delivers into the creation runtime, and
|
|
217
|
+
// rebinding it to a worklet runtime would invoke main-runtime
|
|
218
|
+
// jsi::Functions on the wrong runtime and thread.
|
|
219
219
|
auto *originalRuntime = instance->getCreationRuntime();
|
|
220
220
|
auto value = Derived::create(rt, instance);
|
|
221
221
|
if (originalRuntime != nullptr) {
|
|
@@ -262,10 +262,37 @@ public:
|
|
|
262
262
|
}
|
|
263
263
|
|
|
264
264
|
/**
|
|
265
|
-
*
|
|
265
|
+
* Returns the JS wrapper of `instance` on `runtime`, creating it on first
|
|
266
|
+
* use.
|
|
267
|
+
*
|
|
268
|
+
* A native object has at most one live wrapper per runtime. The wrapper is
|
|
269
|
+
* cached (weakly, so it stays collectable) in the runtime's JSICache, and
|
|
270
|
+
* converting the same object again (returning it from another native
|
|
271
|
+
* call, unboxing it in a worklet on every frame, ...) hands back that
|
|
272
|
+
* wrapper instead of a new one. Each wrapper reports the native memory the
|
|
273
|
+
* object owns to the GC of its runtime through setExternalMemoryPressure,
|
|
274
|
+
* so the memory is charged exactly once per runtime that can reach the
|
|
275
|
+
* object, however often it is converted; charging every conversion used
|
|
276
|
+
* to multiply the amount by the number of captures in a worklet until
|
|
277
|
+
* Hermes hit its max heap size. The hint is refreshed on every round trip
|
|
278
|
+
* for objects whose size changes after creation (path and paragraph
|
|
279
|
+
* builders).
|
|
266
280
|
*/
|
|
267
281
|
static jsi::Value create(jsi::Runtime &runtime,
|
|
268
282
|
std::shared_ptr<Derived> instance) {
|
|
283
|
+
auto &cache = JSICache::get(runtime);
|
|
284
|
+
const void *key = instance.get();
|
|
285
|
+
|
|
286
|
+
auto existing = cache.lockWrapper(runtime, key);
|
|
287
|
+
if (existing.isObject()) {
|
|
288
|
+
auto pressure = instance->getMemoryPressure();
|
|
289
|
+
if (pressure > 0) {
|
|
290
|
+
existing.getObject(runtime).setExternalMemoryPressure(runtime,
|
|
291
|
+
pressure);
|
|
292
|
+
}
|
|
293
|
+
return existing;
|
|
294
|
+
}
|
|
295
|
+
|
|
269
296
|
// Store creation runtime for logging etc.
|
|
270
297
|
instance->setCreationRuntime(&runtime);
|
|
271
298
|
|
|
@@ -290,9 +317,11 @@ public:
|
|
|
290
317
|
obj.setExternalMemoryPressure(runtime, pressure);
|
|
291
318
|
}
|
|
292
319
|
|
|
320
|
+
cache.setWrapper(runtime, key, obj);
|
|
293
321
|
return std::move(obj);
|
|
294
322
|
}
|
|
295
323
|
|
|
324
|
+
public:
|
|
296
325
|
/**
|
|
297
326
|
* Get the native state from a JS value.
|
|
298
327
|
* Throws if the value doesn't have the expected native state.
|
|
@@ -112,7 +112,7 @@ public:
|
|
|
112
112
|
int height = static_cast<int>(IOSurfaceGetHeight(ioSurface));
|
|
113
113
|
#else
|
|
114
114
|
wgpu::SharedTextureMemoryAHardwareBufferDescriptor platformDesc;
|
|
115
|
-
auto ahb =
|
|
115
|
+
auto ahb = reinterpret_cast<AHardwareBuffer *>(buffer);
|
|
116
116
|
platformDesc.handle = ahb;
|
|
117
117
|
AHardwareBuffer_Desc adesc;
|
|
118
118
|
AHardwareBuffer_describe(ahb, &adesc);
|
|
@@ -9,6 +9,12 @@ var _interpolate = require("./interpolate");
|
|
|
9
9
|
const lerp = (value, from, to, p1, p2) => {
|
|
10
10
|
"worklet";
|
|
11
11
|
|
|
12
|
+
// Zero-width segment (duplicate input stops): t would be NaN or Infinity.
|
|
13
|
+
// Return the segment's end path (p2), i.e. the value jumps to p2 at the stop.
|
|
14
|
+
// reanimated's interpolate has no explicit guard here, so this is our choice.
|
|
15
|
+
if (to === from) {
|
|
16
|
+
return p2;
|
|
17
|
+
}
|
|
12
18
|
const t = (value - from) / (to - from);
|
|
13
19
|
// interpolate returns a new path (immutable operation)
|
|
14
20
|
return p2.interpolate(p1, t);
|
|
@@ -33,12 +39,21 @@ const lerp = (value, from, to, p1, p2) => {
|
|
|
33
39
|
const interpolatePaths = (value, input, outputRange, options, _output) => {
|
|
34
40
|
"worklet";
|
|
35
41
|
|
|
42
|
+
if (input.length < 2 || input.length !== outputRange.length) {
|
|
43
|
+
throw new Error(`interpolatePaths() requires input and outputRange to have the same length and at least 2 entries, received ${input.length} and ${outputRange.length}`);
|
|
44
|
+
}
|
|
45
|
+
if (Number.isNaN(value)) {
|
|
46
|
+
throw new Error("interpolatePaths() received NaN as value");
|
|
47
|
+
}
|
|
36
48
|
const extrapolation = (0, _interpolate.validateInterpolationOptions)(options);
|
|
37
49
|
if (value < input[0]) {
|
|
38
50
|
switch (extrapolation.extrapolateLeft) {
|
|
39
51
|
case _interpolate.Extrapolate.CLAMP:
|
|
40
52
|
return outputRange[0];
|
|
41
53
|
case _interpolate.Extrapolate.EXTEND:
|
|
54
|
+
if (!Number.isFinite(value)) {
|
|
55
|
+
throw new Error("interpolatePaths() cannot extend with an infinite value, use clamp extrapolation instead");
|
|
56
|
+
}
|
|
42
57
|
return lerp(value, input[0], input[1], outputRange[0], outputRange[1]);
|
|
43
58
|
case _interpolate.Extrapolate.IDENTITY:
|
|
44
59
|
throw new Error("Identity is not a supported extrapolation type for interpolatePaths()");
|
|
@@ -50,6 +65,9 @@ const interpolatePaths = (value, input, outputRange, options, _output) => {
|
|
|
50
65
|
case _interpolate.Extrapolate.CLAMP:
|
|
51
66
|
return outputRange[outputRange.length - 1];
|
|
52
67
|
case _interpolate.Extrapolate.EXTEND:
|
|
68
|
+
if (!Number.isFinite(value)) {
|
|
69
|
+
throw new Error("interpolatePaths() cannot extend with an infinite value, use clamp extrapolation instead");
|
|
70
|
+
}
|
|
53
71
|
return lerp(value, input[input.length - 2], input[input.length - 1], outputRange[input.length - 2], outputRange[input.length - 1]);
|
|
54
72
|
case _interpolate.Extrapolate.IDENTITY:
|
|
55
73
|
throw new Error("Identity is not a supported extrapolation type for interpolatePaths()");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_typeddash","require","_interpolate","lerp","value","from","to","p1","p2","t","interpolate","interpolatePaths","input","outputRange","options","_output","extrapolation","validateInterpolationOptions","extrapolateLeft","Extrapolate","CLAMP","EXTEND","
|
|
1
|
+
{"version":3,"names":["_typeddash","require","_interpolate","lerp","value","from","to","p1","p2","t","interpolate","interpolatePaths","input","outputRange","options","_output","length","Error","Number","isNaN","extrapolation","validateInterpolationOptions","extrapolateLeft","Extrapolate","CLAMP","EXTEND","isFinite","IDENTITY","exhaustiveCheck","extrapolateRight","i","exports"],"sources":["interpolatePaths.ts"],"sourcesContent":["import type { SkPath } from \"../../skia/types\";\nimport { exhaustiveCheck } from \"../../renderer/typeddash\";\n\nimport type { ExtrapolationType } from \"./interpolate\";\nimport { validateInterpolationOptions, Extrapolate } from \"./interpolate\";\n\nconst lerp = (\n value: number,\n from: number,\n to: number,\n p1: SkPath,\n p2: SkPath\n) => {\n \"worklet\";\n // Zero-width segment (duplicate input stops): t would be NaN or Infinity.\n // Return the segment's end path (p2), i.e. the value jumps to p2 at the stop.\n // reanimated's interpolate has no explicit guard here, so this is our choice.\n if (to === from) {\n return p2;\n }\n const t = (value - from) / (to - from);\n // interpolate returns a new path (immutable operation)\n return p2.interpolate(p1, t)!;\n};\n\n/**\n * Maps an input value within a range to an output path within a path range.\n * @param value - The input value.\n * @param inputRange - The range of the input value.\n * @param outputRange - The range of the output path.\n * @param options - Extrapolation options\n * @returns The output path.\n * @example <caption>Map a value between 0 and 1 to a path between two paths.</caption>\n * const path1 = new Path();\n * path1.moveTo(0, 0);\n * path1.lineTo(100, 0);\n * const path2 = new Path();\n * path2.moveTo(0, 0);\n * path2.lineTo(0, 100);\n * const path = interpolatePath(0.5, [0, 1], [path1, path2]);\n */\nexport const interpolatePaths = (\n value: number,\n input: number[],\n outputRange: SkPath[],\n options?: ExtrapolationType,\n _output?: SkPath\n) => {\n \"worklet\";\n if (input.length < 2 || input.length !== outputRange.length) {\n throw new Error(\n `interpolatePaths() requires input and outputRange to have the same length and at least 2 entries, received ${input.length} and ${outputRange.length}`\n );\n }\n if (Number.isNaN(value)) {\n throw new Error(\"interpolatePaths() received NaN as value\");\n }\n const extrapolation = validateInterpolationOptions(options);\n if (value < input[0]) {\n switch (extrapolation.extrapolateLeft) {\n case Extrapolate.CLAMP:\n return outputRange[0];\n case Extrapolate.EXTEND:\n if (!Number.isFinite(value)) {\n throw new Error(\n \"interpolatePaths() cannot extend with an infinite value, use clamp extrapolation instead\"\n );\n }\n return lerp(value, input[0], input[1], outputRange[0], outputRange[1]);\n case Extrapolate.IDENTITY:\n throw new Error(\n \"Identity is not a supported extrapolation type for interpolatePaths()\"\n );\n default:\n exhaustiveCheck(extrapolation.extrapolateLeft);\n }\n } else if (value > input[input.length - 1]) {\n switch (extrapolation.extrapolateRight) {\n case Extrapolate.CLAMP:\n return outputRange[outputRange.length - 1];\n case Extrapolate.EXTEND:\n if (!Number.isFinite(value)) {\n throw new Error(\n \"interpolatePaths() cannot extend with an infinite value, use clamp extrapolation instead\"\n );\n }\n return lerp(\n value,\n input[input.length - 2],\n input[input.length - 1],\n outputRange[input.length - 2],\n outputRange[input.length - 1]\n );\n case Extrapolate.IDENTITY:\n throw new Error(\n \"Identity is not a supported extrapolation type for interpolatePaths()\"\n );\n default:\n exhaustiveCheck(extrapolation.extrapolateRight);\n }\n }\n let i = 0;\n for (; i <= input.length - 1; i++) {\n if (value >= input[i] && value <= input[i + 1]) {\n break;\n }\n }\n return lerp(\n value,\n input[i],\n input[i + 1],\n outputRange[i],\n outputRange[i + 1]\n );\n};\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -3,6 +3,12 @@ import { validateInterpolationOptions, Extrapolate } from "./interpolate";
|
|
|
3
3
|
const lerp = (value, from, to, p1, p2) => {
|
|
4
4
|
"worklet";
|
|
5
5
|
|
|
6
|
+
// Zero-width segment (duplicate input stops): t would be NaN or Infinity.
|
|
7
|
+
// Return the segment's end path (p2), i.e. the value jumps to p2 at the stop.
|
|
8
|
+
// reanimated's interpolate has no explicit guard here, so this is our choice.
|
|
9
|
+
if (to === from) {
|
|
10
|
+
return p2;
|
|
11
|
+
}
|
|
6
12
|
const t = (value - from) / (to - from);
|
|
7
13
|
// interpolate returns a new path (immutable operation)
|
|
8
14
|
return p2.interpolate(p1, t);
|
|
@@ -27,12 +33,21 @@ const lerp = (value, from, to, p1, p2) => {
|
|
|
27
33
|
export const interpolatePaths = (value, input, outputRange, options, _output) => {
|
|
28
34
|
"worklet";
|
|
29
35
|
|
|
36
|
+
if (input.length < 2 || input.length !== outputRange.length) {
|
|
37
|
+
throw new Error(`interpolatePaths() requires input and outputRange to have the same length and at least 2 entries, received ${input.length} and ${outputRange.length}`);
|
|
38
|
+
}
|
|
39
|
+
if (Number.isNaN(value)) {
|
|
40
|
+
throw new Error("interpolatePaths() received NaN as value");
|
|
41
|
+
}
|
|
30
42
|
const extrapolation = validateInterpolationOptions(options);
|
|
31
43
|
if (value < input[0]) {
|
|
32
44
|
switch (extrapolation.extrapolateLeft) {
|
|
33
45
|
case Extrapolate.CLAMP:
|
|
34
46
|
return outputRange[0];
|
|
35
47
|
case Extrapolate.EXTEND:
|
|
48
|
+
if (!Number.isFinite(value)) {
|
|
49
|
+
throw new Error("interpolatePaths() cannot extend with an infinite value, use clamp extrapolation instead");
|
|
50
|
+
}
|
|
36
51
|
return lerp(value, input[0], input[1], outputRange[0], outputRange[1]);
|
|
37
52
|
case Extrapolate.IDENTITY:
|
|
38
53
|
throw new Error("Identity is not a supported extrapolation type for interpolatePaths()");
|
|
@@ -44,6 +59,9 @@ export const interpolatePaths = (value, input, outputRange, options, _output) =>
|
|
|
44
59
|
case Extrapolate.CLAMP:
|
|
45
60
|
return outputRange[outputRange.length - 1];
|
|
46
61
|
case Extrapolate.EXTEND:
|
|
62
|
+
if (!Number.isFinite(value)) {
|
|
63
|
+
throw new Error("interpolatePaths() cannot extend with an infinite value, use clamp extrapolation instead");
|
|
64
|
+
}
|
|
47
65
|
return lerp(value, input[input.length - 2], input[input.length - 1], outputRange[input.length - 2], outputRange[input.length - 1]);
|
|
48
66
|
case Extrapolate.IDENTITY:
|
|
49
67
|
throw new Error("Identity is not a supported extrapolation type for interpolatePaths()");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["exhaustiveCheck","validateInterpolationOptions","Extrapolate","lerp","value","from","to","p1","p2","t","interpolate","interpolatePaths","input","outputRange","options","_output","extrapolation","extrapolateLeft","CLAMP","EXTEND","
|
|
1
|
+
{"version":3,"names":["exhaustiveCheck","validateInterpolationOptions","Extrapolate","lerp","value","from","to","p1","p2","t","interpolate","interpolatePaths","input","outputRange","options","_output","length","Error","Number","isNaN","extrapolation","extrapolateLeft","CLAMP","EXTEND","isFinite","IDENTITY","extrapolateRight","i"],"sources":["interpolatePaths.ts"],"sourcesContent":["import type { SkPath } from \"../../skia/types\";\nimport { exhaustiveCheck } from \"../../renderer/typeddash\";\n\nimport type { ExtrapolationType } from \"./interpolate\";\nimport { validateInterpolationOptions, Extrapolate } from \"./interpolate\";\n\nconst lerp = (\n value: number,\n from: number,\n to: number,\n p1: SkPath,\n p2: SkPath\n) => {\n \"worklet\";\n // Zero-width segment (duplicate input stops): t would be NaN or Infinity.\n // Return the segment's end path (p2), i.e. the value jumps to p2 at the stop.\n // reanimated's interpolate has no explicit guard here, so this is our choice.\n if (to === from) {\n return p2;\n }\n const t = (value - from) / (to - from);\n // interpolate returns a new path (immutable operation)\n return p2.interpolate(p1, t)!;\n};\n\n/**\n * Maps an input value within a range to an output path within a path range.\n * @param value - The input value.\n * @param inputRange - The range of the input value.\n * @param outputRange - The range of the output path.\n * @param options - Extrapolation options\n * @returns The output path.\n * @example <caption>Map a value between 0 and 1 to a path between two paths.</caption>\n * const path1 = new Path();\n * path1.moveTo(0, 0);\n * path1.lineTo(100, 0);\n * const path2 = new Path();\n * path2.moveTo(0, 0);\n * path2.lineTo(0, 100);\n * const path = interpolatePath(0.5, [0, 1], [path1, path2]);\n */\nexport const interpolatePaths = (\n value: number,\n input: number[],\n outputRange: SkPath[],\n options?: ExtrapolationType,\n _output?: SkPath\n) => {\n \"worklet\";\n if (input.length < 2 || input.length !== outputRange.length) {\n throw new Error(\n `interpolatePaths() requires input and outputRange to have the same length and at least 2 entries, received ${input.length} and ${outputRange.length}`\n );\n }\n if (Number.isNaN(value)) {\n throw new Error(\"interpolatePaths() received NaN as value\");\n }\n const extrapolation = validateInterpolationOptions(options);\n if (value < input[0]) {\n switch (extrapolation.extrapolateLeft) {\n case Extrapolate.CLAMP:\n return outputRange[0];\n case Extrapolate.EXTEND:\n if (!Number.isFinite(value)) {\n throw new Error(\n \"interpolatePaths() cannot extend with an infinite value, use clamp extrapolation instead\"\n );\n }\n return lerp(value, input[0], input[1], outputRange[0], outputRange[1]);\n case Extrapolate.IDENTITY:\n throw new Error(\n \"Identity is not a supported extrapolation type for interpolatePaths()\"\n );\n default:\n exhaustiveCheck(extrapolation.extrapolateLeft);\n }\n } else if (value > input[input.length - 1]) {\n switch (extrapolation.extrapolateRight) {\n case Extrapolate.CLAMP:\n return outputRange[outputRange.length - 1];\n case Extrapolate.EXTEND:\n if (!Number.isFinite(value)) {\n throw new Error(\n \"interpolatePaths() cannot extend with an infinite value, use clamp extrapolation instead\"\n );\n }\n return lerp(\n value,\n input[input.length - 2],\n input[input.length - 1],\n outputRange[input.length - 2],\n outputRange[input.length - 1]\n );\n case Extrapolate.IDENTITY:\n throw new Error(\n \"Identity is not a supported extrapolation type for interpolatePaths()\"\n );\n default:\n exhaustiveCheck(extrapolation.extrapolateRight);\n }\n }\n let i = 0;\n for (; i <= input.length - 1; i++) {\n if (value >= input[i] && value <= input[i + 1]) {\n break;\n }\n }\n return lerp(\n value,\n input[i],\n input[i + 1],\n outputRange[i],\n outputRange[i + 1]\n );\n};\n"],"mappings":"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","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"setup-skia-web": "scripts/setup-canvaskit.js"
|
|
9
9
|
},
|
|
10
10
|
"title": "React Native Skia",
|
|
11
|
-
"version": "2.13.
|
|
11
|
+
"version": "2.13.1",
|
|
12
12
|
"description": "High-performance React Native Graphics using Skia",
|
|
13
13
|
"main": "lib/module/index.js",
|
|
14
14
|
"react-native": "src/index.ts",
|
|
@@ -12,6 +12,12 @@ const lerp = (
|
|
|
12
12
|
p2: SkPath
|
|
13
13
|
) => {
|
|
14
14
|
"worklet";
|
|
15
|
+
// Zero-width segment (duplicate input stops): t would be NaN or Infinity.
|
|
16
|
+
// Return the segment's end path (p2), i.e. the value jumps to p2 at the stop.
|
|
17
|
+
// reanimated's interpolate has no explicit guard here, so this is our choice.
|
|
18
|
+
if (to === from) {
|
|
19
|
+
return p2;
|
|
20
|
+
}
|
|
15
21
|
const t = (value - from) / (to - from);
|
|
16
22
|
// interpolate returns a new path (immutable operation)
|
|
17
23
|
return p2.interpolate(p1, t)!;
|
|
@@ -41,12 +47,25 @@ export const interpolatePaths = (
|
|
|
41
47
|
_output?: SkPath
|
|
42
48
|
) => {
|
|
43
49
|
"worklet";
|
|
50
|
+
if (input.length < 2 || input.length !== outputRange.length) {
|
|
51
|
+
throw new Error(
|
|
52
|
+
`interpolatePaths() requires input and outputRange to have the same length and at least 2 entries, received ${input.length} and ${outputRange.length}`
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
if (Number.isNaN(value)) {
|
|
56
|
+
throw new Error("interpolatePaths() received NaN as value");
|
|
57
|
+
}
|
|
44
58
|
const extrapolation = validateInterpolationOptions(options);
|
|
45
59
|
if (value < input[0]) {
|
|
46
60
|
switch (extrapolation.extrapolateLeft) {
|
|
47
61
|
case Extrapolate.CLAMP:
|
|
48
62
|
return outputRange[0];
|
|
49
63
|
case Extrapolate.EXTEND:
|
|
64
|
+
if (!Number.isFinite(value)) {
|
|
65
|
+
throw new Error(
|
|
66
|
+
"interpolatePaths() cannot extend with an infinite value, use clamp extrapolation instead"
|
|
67
|
+
);
|
|
68
|
+
}
|
|
50
69
|
return lerp(value, input[0], input[1], outputRange[0], outputRange[1]);
|
|
51
70
|
case Extrapolate.IDENTITY:
|
|
52
71
|
throw new Error(
|
|
@@ -60,6 +79,11 @@ export const interpolatePaths = (
|
|
|
60
79
|
case Extrapolate.CLAMP:
|
|
61
80
|
return outputRange[outputRange.length - 1];
|
|
62
81
|
case Extrapolate.EXTEND:
|
|
82
|
+
if (!Number.isFinite(value)) {
|
|
83
|
+
throw new Error(
|
|
84
|
+
"interpolatePaths() cannot extend with an infinite value, use clamp extrapolation instead"
|
|
85
|
+
);
|
|
86
|
+
}
|
|
63
87
|
return lerp(
|
|
64
88
|
value,
|
|
65
89
|
input[input.length - 2],
|