@shopify/react-native-skia 2.13.0 → 2.14.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/android/CMakeLists.txt +2 -0
- package/android/cpp/jni/include/JniSkiaPictureView.h +16 -15
- package/android/cpp/rnskia-android/OpenGLContext.h +1 -1
- package/android/cpp/rnskia-android/gl/Surface.h +1 -1
- package/apple/RNSkApplePlatformContext.h +3 -4
- package/apple/RNSkiaModule.h +11 -3
- package/apple/RNSkiaModule.mm +46 -19
- package/apple/SkiaPictureView.mm +2 -2
- package/apple/SkiaUIView.h +0 -1
- package/apple/SkiaUIView.mm +1 -1
- package/apple/ViewScreenshotService.h +2 -2
- package/apple/ViewScreenshotService.mm +5 -4
- 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 -435
- 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 +29 -28
- package/cpp/api/JsiSkStrutStyle.h +1 -1
- package/cpp/api/JsiSkSurfaceFactory.h +41 -0
- package/cpp/api/recorder/Command.h +1 -1
- package/cpp/api/recorder/Convertor.h +153 -132
- package/cpp/api/recorder/DataTypes.h +12 -12
- package/cpp/api/recorder/DrawingCtx.h +1 -1
- package/cpp/api/recorder/ImageFit.h +8 -5
- package/cpp/api/recorder/JsiRecorder.h +14 -31
- package/cpp/api/recorder/Paint.h +3 -3
- package/cpp/api/recorder/RNRecorder.h +56 -0
- 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/jsi/ViewProperty.cpp +23 -0
- package/cpp/jsi/ViewProperty.h +31 -10
- package/cpp/rnskia/RNDawnContext.h +34 -1
- package/cpp/rnskia/RNSkJsiViewApi.h +69 -2
- package/cpp/rnskia/RNSkPictureView.cpp +58 -0
- package/cpp/rnskia/RNSkPictureView.h +110 -24
- package/lib/commonjs/Platform/IPlatform.js.map +1 -1
- package/lib/commonjs/animation/functions/interpolate.js.map +1 -1
- package/lib/commonjs/animation/functions/interpolatePaths.js +18 -0
- package/lib/commonjs/animation/functions/interpolatePaths.js.map +1 -1
- package/lib/commonjs/skia/core/Image.js.map +1 -1
- package/lib/commonjs/skia/types/NativeBuffer/NativeBufferFactory.js.map +1 -1
- package/lib/commonjs/skia/types/Path/Path.d.ts +2 -336
- package/lib/commonjs/skia/types/Path/Path.js.map +1 -1
- package/lib/commonjs/skia/types/Recorder.d.ts +10 -0
- package/lib/commonjs/skia/types/Recorder.js.map +1 -1
- package/lib/commonjs/skia/types/Shader/Shader.js.map +1 -1
- package/lib/commonjs/skia/types/Surface/SurfaceFactory.d.ts +16 -0
- package/lib/commonjs/skia/types/Surface/SurfaceFactory.js.map +1 -1
- package/lib/commonjs/skia/web/JsiSkPath.d.ts +4 -38
- package/lib/commonjs/skia/web/JsiSkPath.js +3 -275
- package/lib/commonjs/skia/web/JsiSkPath.js.map +1 -1
- package/lib/commonjs/skia/web/JsiSkSurfaceFactory.d.ts +2 -1
- package/lib/commonjs/skia/web/JsiSkSurfaceFactory.js +3 -0
- package/lib/commonjs/skia/web/JsiSkSurfaceFactory.js.map +1 -1
- package/lib/commonjs/sksg/Container.native.d.ts +15 -1
- package/lib/commonjs/sksg/Container.native.js +34 -33
- package/lib/commonjs/sksg/Container.native.js.map +1 -1
- package/lib/commonjs/specs/NativeSkiaModule.web.js +4 -0
- package/lib/commonjs/specs/NativeSkiaModule.web.js.map +1 -1
- package/lib/commonjs/views/types.d.ts +9 -0
- package/lib/commonjs/views/types.js.map +1 -1
- package/lib/module/Platform/IPlatform.js.map +1 -1
- package/lib/module/animation/functions/interpolate.js.map +1 -1
- package/lib/module/animation/functions/interpolatePaths.js +18 -0
- package/lib/module/animation/functions/interpolatePaths.js.map +1 -1
- package/lib/module/skia/core/Image.js.map +1 -1
- package/lib/module/skia/types/NativeBuffer/NativeBufferFactory.js.map +1 -1
- package/lib/module/skia/types/Path/Path.d.ts +2 -336
- package/lib/module/skia/types/Path/Path.js.map +1 -1
- package/lib/module/skia/types/Recorder.d.ts +10 -0
- package/lib/module/skia/types/Recorder.js.map +1 -1
- package/lib/module/skia/types/Shader/Shader.js.map +1 -1
- package/lib/module/skia/types/Surface/SurfaceFactory.d.ts +16 -0
- package/lib/module/skia/types/Surface/SurfaceFactory.js.map +1 -1
- package/lib/module/skia/web/JsiSkPath.d.ts +4 -38
- package/lib/module/skia/web/JsiSkPath.js +4 -276
- package/lib/module/skia/web/JsiSkPath.js.map +1 -1
- package/lib/module/skia/web/JsiSkSurfaceFactory.d.ts +2 -1
- package/lib/module/skia/web/JsiSkSurfaceFactory.js +4 -1
- package/lib/module/skia/web/JsiSkSurfaceFactory.js.map +1 -1
- package/lib/module/sksg/Container.native.d.ts +15 -1
- package/lib/module/sksg/Container.native.js +34 -33
- package/lib/module/sksg/Container.native.js.map +1 -1
- package/lib/module/specs/NativeSkiaModule.web.js +4 -0
- package/lib/module/specs/NativeSkiaModule.web.js.map +1 -1
- package/lib/module/views/types.d.ts +9 -0
- package/lib/module/views/types.js.map +1 -1
- package/lib/typescript/lib/commonjs/skia/web/JsiSkPath.d.ts +1 -35
- package/lib/typescript/lib/commonjs/skia/web/JsiSkSurfaceFactory.d.ts +1 -0
- package/lib/typescript/lib/commonjs/sksg/Container.native.d.ts +15 -1
- package/lib/typescript/lib/module/skia/web/JsiSkPath.d.ts +3 -37
- package/lib/typescript/lib/module/skia/web/JsiSkSurfaceFactory.d.ts +1 -0
- package/lib/typescript/lib/module/sksg/Container.native.d.ts +15 -1
- package/lib/typescript/src/skia/types/Path/Path.d.ts +2 -336
- package/lib/typescript/src/skia/types/Recorder.d.ts +10 -0
- package/lib/typescript/src/skia/types/Surface/SurfaceFactory.d.ts +16 -0
- package/lib/typescript/src/skia/web/JsiSkPath.d.ts +4 -38
- package/lib/typescript/src/skia/web/JsiSkSurfaceFactory.d.ts +2 -1
- package/lib/typescript/src/sksg/Container.native.d.ts +15 -1
- package/lib/typescript/src/views/types.d.ts +9 -0
- package/package.json +2 -2
- package/src/Platform/IPlatform.ts +1 -4
- package/src/animation/functions/interpolate.ts +1 -4
- package/src/animation/functions/interpolatePaths.ts +24 -0
- package/src/skia/core/Image.ts +1 -2
- package/src/skia/types/NativeBuffer/NativeBufferFactory.ts +2 -5
- package/src/skia/types/Path/Path.ts +2 -420
- package/src/skia/types/Recorder.ts +10 -0
- package/src/skia/types/Shader/Shader.ts +1 -5
- package/src/skia/types/Surface/SurfaceFactory.ts +17 -0
- package/src/skia/web/JsiSkPath.ts +4 -495
- package/src/skia/web/JsiSkSurfaceFactory.ts +6 -2
- package/src/sksg/Container.native.ts +34 -37
- package/src/specs/NativeSkiaModule.web.ts +4 -0
- package/src/views/types.ts +13 -0
- package/apple/SkiaManager.h +0 -23
- package/apple/SkiaManager.mm +0 -63
|
@@ -73,6 +73,19 @@ public:
|
|
|
73
73
|
return func(info);
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
// Runs func on an existing entry under the registry's shared lock. Unlike
|
|
77
|
+
// withViewInfo(), this never creates an entry: func is not called for an
|
|
78
|
+
// unknown id. Other readers may hold the entry at the same time, so func
|
|
79
|
+
// must not modify it; the objects its props reference may be modified
|
|
80
|
+
// under their own lock.
|
|
81
|
+
template <typename F> void withExistingViewInfo(size_t id, F &&func) {
|
|
82
|
+
std::shared_lock<std::shared_mutex> lock(_mutex);
|
|
83
|
+
auto it = _registry.find(id);
|
|
84
|
+
if (it != _registry.end()) {
|
|
85
|
+
func(it->second);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
76
89
|
// Read-only lookup: never creates a registry entry.
|
|
77
90
|
std::shared_ptr<RNSkView> getView(size_t id) {
|
|
78
91
|
std::shared_lock<std::shared_mutex> lock(_mutex);
|
|
@@ -130,8 +143,7 @@ public:
|
|
|
130
143
|
nativeId, [&](std::shared_ptr<RNSkViewInfo> info) {
|
|
131
144
|
auto name = arguments[1].asString(runtime).utf8(runtime);
|
|
132
145
|
info->props.insert_or_assign(
|
|
133
|
-
arguments[
|
|
134
|
-
RNJsi::ViewProperty(runtime, arguments[2]));
|
|
146
|
+
name, RNJsi::ViewProperty(runtime, arguments[2]));
|
|
135
147
|
// Now let's see if we have a view that we can update
|
|
136
148
|
if (info->view != nullptr) {
|
|
137
149
|
// Update view!
|
|
@@ -170,6 +182,59 @@ public:
|
|
|
170
182
|
return jsi::Value::undefined();
|
|
171
183
|
}
|
|
172
184
|
|
|
185
|
+
/**
|
|
186
|
+
Reads the given shared values into the recording held for the view and
|
|
187
|
+
schedules a redraw. Called from the Reanimated mapper on every frame; the
|
|
188
|
+
only things crossing runtimes are the view id, the recording id and the
|
|
189
|
+
shared values. The recording is either owned by the view or, until the
|
|
190
|
+
view registers, queued for it in the registry. Updates for a recording
|
|
191
|
+
that is neither (a stale mapper, a view that has been torn down) are
|
|
192
|
+
ignored.
|
|
193
|
+
*/
|
|
194
|
+
JSI_HOST_FUNCTION(applyUpdates) {
|
|
195
|
+
if (count != 3 || !arguments[0].isNumber() || !arguments[1].isNumber() ||
|
|
196
|
+
!arguments[2].isObject() ||
|
|
197
|
+
!arguments[2].asObject(runtime).isArray(runtime)) {
|
|
198
|
+
_platformContext->raiseError(
|
|
199
|
+
"applyUpdates: expected (nativeId: number, recorderId: number, "
|
|
200
|
+
"values: SharedValue[])");
|
|
201
|
+
return jsi::Value::undefined();
|
|
202
|
+
}
|
|
203
|
+
int nativeId = arguments[0].asNumber();
|
|
204
|
+
auto recorderId = arguments[1].asNumber();
|
|
205
|
+
auto values = arguments[2].asObject(runtime).asArray(runtime);
|
|
206
|
+
std::shared_ptr<RNSkView> view;
|
|
207
|
+
ViewRegistry::getInstance().withExistingViewInfo(
|
|
208
|
+
nativeId, [&](const std::shared_ptr<RNSkViewInfo> &info) {
|
|
209
|
+
view = info->view;
|
|
210
|
+
if (view != nullptr) {
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
// The view has not registered yet (or is detached, which on iOS
|
|
214
|
+
// destroys it): the recording waits in the registry and is drawn,
|
|
215
|
+
// with whatever values it holds by then, once a view registers.
|
|
216
|
+
// Keep it current, under the registry lock so that a registration
|
|
217
|
+
// cannot slip in between; the first frame would otherwise show
|
|
218
|
+
// the values from recording time until the next change.
|
|
219
|
+
auto it = info->props.find("recorder");
|
|
220
|
+
if (it != info->props.end() && it->second.isRecorder()) {
|
|
221
|
+
RNSkPictureRenderer::applyUpdatesTo(it->second.getRecorder(),
|
|
222
|
+
runtime, recorderId, values);
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
if (view == nullptr) {
|
|
226
|
+
return jsi::Value::undefined();
|
|
227
|
+
}
|
|
228
|
+
// Outside the registry lock: the update must not hold up the commits
|
|
229
|
+
// and registrations of other views.
|
|
230
|
+
auto renderer =
|
|
231
|
+
std::static_pointer_cast<RNSkPictureRenderer>(view->getRenderer());
|
|
232
|
+
if (renderer->applyUpdates(runtime, recorderId, values)) {
|
|
233
|
+
view->requestRedraw();
|
|
234
|
+
}
|
|
235
|
+
return jsi::Value::undefined();
|
|
236
|
+
}
|
|
237
|
+
|
|
173
238
|
JSI_HOST_FUNCTION(makeImageSnapshot) {
|
|
174
239
|
if (count < 1) {
|
|
175
240
|
_platformContext->raiseError(
|
|
@@ -293,6 +358,8 @@ public:
|
|
|
293
358
|
&RNSkJsiViewApi::setJsiProperty);
|
|
294
359
|
installHostMethod(runtime, prototype, "requestRedraw",
|
|
295
360
|
&RNSkJsiViewApi::requestRedraw);
|
|
361
|
+
installHostMethod(runtime, prototype, "applyUpdates",
|
|
362
|
+
&RNSkJsiViewApi::applyUpdates);
|
|
296
363
|
installHostMethod(runtime, prototype, "makeImageSnapshotAsync",
|
|
297
364
|
&RNSkJsiViewApi::makeImageSnapshotAsync);
|
|
298
365
|
installHostMethod(runtime, prototype, "makeImageSnapshot",
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// The recorder headers depend on the include order established by
|
|
2
|
+
// JsiSkApi.h, so everything that needs a complete Recorder lives here rather
|
|
3
|
+
// than in RNSkPictureView.h (which platform views include on its own).
|
|
4
|
+
#include "api/JsiSkApi.h"
|
|
5
|
+
|
|
6
|
+
#include "RNSkPictureView.h"
|
|
7
|
+
|
|
8
|
+
#include "api/recorder/DrawingCtx.h"
|
|
9
|
+
#include "api/recorder/RNRecorder.h"
|
|
10
|
+
|
|
11
|
+
namespace RNSkia {
|
|
12
|
+
|
|
13
|
+
void RNSkPictureRenderer::setRecorder(std::shared_ptr<Recorder> recorder) {
|
|
14
|
+
sk_sp<SkPicture> picture;
|
|
15
|
+
if (recorder != nullptr && recorder->variables.empty()) {
|
|
16
|
+
picture = recorder->makePicture();
|
|
17
|
+
recorder = nullptr;
|
|
18
|
+
}
|
|
19
|
+
std::shared_ptr<Recorder> retired;
|
|
20
|
+
{
|
|
21
|
+
std::lock_guard<std::mutex> lock(_mutex);
|
|
22
|
+
retired = std::move(_recorder);
|
|
23
|
+
_recorder = std::move(recorder);
|
|
24
|
+
_picture = std::move(picture);
|
|
25
|
+
}
|
|
26
|
+
retired = nullptr;
|
|
27
|
+
_requestRedraw();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
bool RNSkPictureRenderer::applyUpdatesTo(
|
|
31
|
+
const std::shared_ptr<Recorder> &recorder, jsi::Runtime &runtime,
|
|
32
|
+
double recorderId, const jsi::Array &values) {
|
|
33
|
+
if (recorder == nullptr || recorder->id != recorderId) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
recorder->applyUpdates(runtime, values);
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
bool RNSkPictureRenderer::applyUpdates(jsi::Runtime &runtime, double recorderId,
|
|
41
|
+
const jsi::Array &values) {
|
|
42
|
+
std::shared_ptr<Recorder> recorder;
|
|
43
|
+
{
|
|
44
|
+
std::lock_guard<std::mutex> lock(_mutex);
|
|
45
|
+
recorder = _recorder;
|
|
46
|
+
}
|
|
47
|
+
// Outside the renderer lock: a commit replacing the recorder must not wait
|
|
48
|
+
// for the update. Should it land while this runs, the update goes into the
|
|
49
|
+
// retired recorder and the redraw that follows draws the new one.
|
|
50
|
+
return applyUpdatesTo(recorder, runtime, recorderId, values);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
void RNSkPictureRenderer::replay(SkCanvas *canvas, Recorder *recorder) {
|
|
54
|
+
DrawingCtx ctx(canvas);
|
|
55
|
+
recorder->play(&ctx);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
} // namespace RNSkia
|
|
@@ -35,6 +35,24 @@ namespace RNSkia {
|
|
|
35
35
|
|
|
36
36
|
namespace jsi = facebook::jsi;
|
|
37
37
|
|
|
38
|
+
class Recorder;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Draws either an SkPicture (imperative API, or a recording without shared
|
|
42
|
+
* values, played once into a picture) or a Recorder (declarative <Canvas>
|
|
43
|
+
* driven by Reanimated shared values). The recorder is owned by the
|
|
44
|
+
* renderer, not by a JS wrapper: its commands hold every native resource the
|
|
45
|
+
* canvas draws (images, pictures, paths), and tying their lifetime to the
|
|
46
|
+
* garbage collector of a runtime that rarely allocates (the UI runtime) kept
|
|
47
|
+
* them resident long after unmount. Here they are released as soon as the
|
|
48
|
+
* recorder is replaced, or when the host view is torn down (see clear()).
|
|
49
|
+
*
|
|
50
|
+
* Threading: setPicture/setRecorder run on the JS thread (React commit),
|
|
51
|
+
* applyUpdates on the UI thread (Reanimated mapper), drawInto on the main
|
|
52
|
+
* thread (onscreen draws) or the JS thread (snapshots). _mutex only guards
|
|
53
|
+
* the two pointers, so a commit never waits for a draw; the recorder
|
|
54
|
+
* serializes its replay against its updates on its own.
|
|
55
|
+
*/
|
|
38
56
|
class RNSkPictureRenderer
|
|
39
57
|
: public RNSkRenderer,
|
|
40
58
|
public std::enable_shared_from_this<RNSkPictureRenderer> {
|
|
@@ -52,31 +70,102 @@ public:
|
|
|
52
70
|
}
|
|
53
71
|
|
|
54
72
|
void setPicture(sk_sp<SkPicture> picture) {
|
|
55
|
-
|
|
73
|
+
{
|
|
74
|
+
std::lock_guard<std::mutex> lock(_mutex);
|
|
75
|
+
_picture = picture;
|
|
76
|
+
_recorder = nullptr;
|
|
77
|
+
}
|
|
56
78
|
_requestRedraw();
|
|
57
79
|
}
|
|
58
80
|
|
|
59
|
-
|
|
81
|
+
/**
|
|
82
|
+
* Takes ownership of a recorder. A recording without shared values is
|
|
83
|
+
* played once into a picture here (and its commands released): nothing
|
|
84
|
+
* will ever update it, and drawing a picture on every redraw (resize,
|
|
85
|
+
* foreground, ref.redraw(), snapshots) is cheaper than replaying commands.
|
|
86
|
+
* The previous recorder (and the resources its commands reference) is
|
|
87
|
+
* released here; Recorder's destructor moves the commands to the main
|
|
88
|
+
* thread before destroying them so GPU-backed resources are freed on the
|
|
89
|
+
* thread that used them.
|
|
90
|
+
*/
|
|
91
|
+
void setRecorder(std::shared_ptr<Recorder> recorder);
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Drops the recorder and the picture without scheduling a redraw. Called
|
|
95
|
+
* when the host view is torn down, so that the resources go away with the
|
|
96
|
+
* view rather than with the garbage collection of its host object (on
|
|
97
|
+
* Android the native view is only destroyed when the Java view is
|
|
98
|
+
* finalized).
|
|
99
|
+
*/
|
|
100
|
+
void clear() {
|
|
101
|
+
std::shared_ptr<Recorder> retired;
|
|
102
|
+
sk_sp<SkPicture> picture;
|
|
103
|
+
{
|
|
104
|
+
std::lock_guard<std::mutex> lock(_mutex);
|
|
105
|
+
retired = std::move(_recorder);
|
|
106
|
+
picture = std::move(_picture);
|
|
107
|
+
}
|
|
108
|
+
// Both are destroyed here, outside the lock.
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Reads the shared values on the calling runtime into the recorder's
|
|
113
|
+
* commands. Returns false when there is no recorder to update, or when the
|
|
114
|
+
* view holds a different recording than recorderId (a stale mapper whose
|
|
115
|
+
* values would otherwise land in the new recording's slots).
|
|
116
|
+
*/
|
|
117
|
+
bool applyUpdates(jsi::Runtime &runtime, double recorderId,
|
|
118
|
+
const jsi::Array &values);
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Same as applyUpdates(), for a recording that no view owns yet (one
|
|
122
|
+
* queued in the view registry until its view registers).
|
|
123
|
+
*/
|
|
124
|
+
static bool applyUpdatesTo(const std::shared_ptr<Recorder> &recorder,
|
|
125
|
+
jsi::Runtime &runtime, double recorderId,
|
|
126
|
+
const jsi::Array &values);
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Draws the current content (recorder or picture) into the canvas, scaled
|
|
130
|
+
* by the pixel density. Used for onscreen draws, snapshots and the Android
|
|
131
|
+
* bitmap export.
|
|
132
|
+
*/
|
|
133
|
+
void drawInto(SkCanvas *canvas, float pixelDensity) {
|
|
134
|
+
// Copy the content under the lock and draw from the copies: a React
|
|
135
|
+
// commit swapping the content must only ever wait for a pointer swap,
|
|
136
|
+
// never for a draw. If the recorder is replaced mid-draw, this frame
|
|
137
|
+
// finishes with the old one and the swap schedules the next frame.
|
|
138
|
+
std::shared_ptr<Recorder> recorder;
|
|
139
|
+
sk_sp<SkPicture> picture;
|
|
140
|
+
{
|
|
141
|
+
std::lock_guard<std::mutex> lock(_mutex);
|
|
142
|
+
recorder = _recorder;
|
|
143
|
+
picture = _picture;
|
|
144
|
+
}
|
|
145
|
+
canvas->clear(SK_ColorTRANSPARENT);
|
|
146
|
+
canvas->save();
|
|
147
|
+
canvas->scale(pixelDensity, pixelDensity);
|
|
148
|
+
if (recorder != nullptr) {
|
|
149
|
+
replay(canvas, recorder.get());
|
|
150
|
+
} else if (picture != nullptr) {
|
|
151
|
+
canvas->drawPicture(picture);
|
|
152
|
+
}
|
|
153
|
+
canvas->restore();
|
|
154
|
+
}
|
|
60
155
|
|
|
61
156
|
private:
|
|
157
|
+
void replay(SkCanvas *canvas, Recorder *recorder);
|
|
158
|
+
|
|
62
159
|
bool performDraw(std::shared_ptr<RNSkCanvasProvider> canvasProvider) {
|
|
63
|
-
// Capture picture pointer to ensure thread safety - _picture can be
|
|
64
|
-
// modified from the JS thread while we're drawing on the render thread
|
|
65
|
-
sk_sp<SkPicture> picture = _picture;
|
|
66
160
|
auto pd = _platformContext->getPixelDensity();
|
|
67
|
-
return canvasProvider->renderToCanvas(
|
|
68
|
-
|
|
69
|
-
canvas->save();
|
|
70
|
-
canvas->scale(pd, pd);
|
|
71
|
-
if (picture != nullptr) {
|
|
72
|
-
canvas->drawPicture(picture);
|
|
73
|
-
}
|
|
74
|
-
canvas->restore();
|
|
75
|
-
});
|
|
161
|
+
return canvasProvider->renderToCanvas(
|
|
162
|
+
[this, pd](SkCanvas *canvas) { drawInto(canvas, pd); });
|
|
76
163
|
}
|
|
77
164
|
|
|
78
165
|
std::shared_ptr<RNSkPlatformContext> _platformContext;
|
|
166
|
+
mutable std::mutex _mutex;
|
|
79
167
|
sk_sp<SkPicture> _picture;
|
|
168
|
+
std::shared_ptr<Recorder> _recorder;
|
|
80
169
|
};
|
|
81
170
|
|
|
82
171
|
class RNSkPictureView : public RNSkView {
|
|
@@ -93,18 +182,15 @@ public:
|
|
|
93
182
|
|
|
94
183
|
void setJsiProperties(
|
|
95
184
|
std::unordered_map<std::string, RNJsi::ViewProperty> &props) override {
|
|
96
|
-
|
|
185
|
+
auto renderer =
|
|
186
|
+
std::static_pointer_cast<RNSkPictureRenderer>(getRenderer());
|
|
97
187
|
for (auto &prop : props) {
|
|
98
188
|
if (prop.first == "picture") {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
// Save picture
|
|
106
|
-
std::static_pointer_cast<RNSkPictureRenderer>(getRenderer())
|
|
107
|
-
->setPicture(prop.second.getPicture());
|
|
189
|
+
renderer->setPicture(prop.second.isPicture() ? prop.second.getPicture()
|
|
190
|
+
: nullptr);
|
|
191
|
+
} else if (prop.first == "recorder") {
|
|
192
|
+
renderer->setRecorder(
|
|
193
|
+
prop.second.isRecorder() ? prop.second.getRecorder() : nullptr);
|
|
108
194
|
}
|
|
109
195
|
}
|
|
110
196
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["IPlatform.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport type { NodeHandle, ViewComponent } from \"react-native\";\n\nimport type { DataModule } from \"../skia/types\";\n\nexport interface IPlatform {\n OS: string;\n PixelRatio: number;\n findNodeHandle: (\n componentOrHandle:\n
|
|
1
|
+
{"version":3,"names":[],"sources":["IPlatform.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport type { NodeHandle, ViewComponent } from \"react-native\";\n\nimport type { DataModule } from \"../skia/types\";\n\nexport interface IPlatform {\n OS: string;\n PixelRatio: number;\n findNodeHandle: (\n componentOrHandle:\n null | number | React.Component<any, any> | React.ComponentClass<any>\n ) => null | NodeHandle;\n resolveAsset: (source: DataModule) => string;\n View: typeof ViewComponent;\n}\n"],"mappings":"","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["Extrapolate","exports","getVal","type","coef","val","leftEdgeOutput","rightEdgeOutput","x","IDENTITY","CLAMP","EXTEND","isExtrapolate","value","validateInterpolationOptions","extrapolationConfig","extrapolateLeft","extrapolateRight","Error","Object","assign","internalInterpolate","narrowedInput","leftEdgeInput","rightEdgeInput","progress","interpolate","input","output","length","i"],"sources":["interpolate.ts"],"sourcesContent":["export enum Extrapolate {\n IDENTITY = \"identity\",\n CLAMP = \"clamp\",\n EXTEND = \"extend\",\n}\n\ninterface InterpolationNarrowedInput {\n leftEdgeInput: number;\n rightEdgeInput: number;\n leftEdgeOutput: number;\n rightEdgeOutput: number;\n}\n\nexport interface ExtrapolationConfig {\n extrapolateLeft?: Extrapolate | string;\n extrapolateRight?: Extrapolate | string;\n}\n\ninterface RequiredExtrapolationConfig {\n extrapolateLeft: Extrapolate;\n extrapolateRight: Extrapolate;\n}\n\nexport type ExtrapolationType =\n
|
|
1
|
+
{"version":3,"names":["Extrapolate","exports","getVal","type","coef","val","leftEdgeOutput","rightEdgeOutput","x","IDENTITY","CLAMP","EXTEND","isExtrapolate","value","validateInterpolationOptions","extrapolationConfig","extrapolateLeft","extrapolateRight","Error","Object","assign","internalInterpolate","narrowedInput","leftEdgeInput","rightEdgeInput","progress","interpolate","input","output","length","i"],"sources":["interpolate.ts"],"sourcesContent":["export enum Extrapolate {\n IDENTITY = \"identity\",\n CLAMP = \"clamp\",\n EXTEND = \"extend\",\n}\n\ninterface InterpolationNarrowedInput {\n leftEdgeInput: number;\n rightEdgeInput: number;\n leftEdgeOutput: number;\n rightEdgeOutput: number;\n}\n\nexport interface ExtrapolationConfig {\n extrapolateLeft?: Extrapolate | string;\n extrapolateRight?: Extrapolate | string;\n}\n\ninterface RequiredExtrapolationConfig {\n extrapolateLeft: Extrapolate;\n extrapolateRight: Extrapolate;\n}\n\nexport type ExtrapolationType =\n ExtrapolationConfig | Extrapolate | string | undefined;\n\nfunction getVal(\n type: Extrapolate,\n coef: number,\n val: number,\n leftEdgeOutput: number,\n rightEdgeOutput: number,\n x: number\n): number {\n \"worklet\";\n switch (type) {\n case Extrapolate.IDENTITY:\n return x;\n case Extrapolate.CLAMP:\n if (coef * val < coef * leftEdgeOutput) {\n return leftEdgeOutput;\n }\n return rightEdgeOutput;\n case Extrapolate.EXTEND:\n default:\n return val;\n }\n}\n\nfunction isExtrapolate(value: string): value is Extrapolate {\n \"worklet\";\n return (\n value === Extrapolate.EXTEND ||\n value === Extrapolate.CLAMP ||\n value === Extrapolate.IDENTITY\n );\n}\n\n// validates extrapolations type\n// if type is correct, converts it to ExtrapolationConfig\nexport function validateInterpolationOptions(\n type: ExtrapolationType\n): RequiredExtrapolationConfig {\n \"worklet\";\n // initialize extrapolationConfig with default extrapolation\n const extrapolationConfig: RequiredExtrapolationConfig = {\n extrapolateLeft: Extrapolate.EXTEND,\n extrapolateRight: Extrapolate.EXTEND,\n };\n\n if (!type) {\n return extrapolationConfig;\n }\n\n if (typeof type === \"string\") {\n if (!isExtrapolate(type)) {\n throw new Error(\n `No supported value for \"interpolate\" \\nSupported values: [\"extend\", \"clamp\", \"identity\", Extrapolatation.CLAMP, Extrapolatation.EXTEND, Extrapolatation.IDENTITY]\\n Valid example:\n interpolate(value, [inputRange], [outputRange], \"clamp\")`\n );\n }\n extrapolationConfig.extrapolateLeft = type;\n extrapolationConfig.extrapolateRight = type;\n return extrapolationConfig;\n }\n\n // otherwise type is extrapolation config object\n if (\n (type.extrapolateLeft && !isExtrapolate(type.extrapolateLeft)) ||\n (type.extrapolateRight && !isExtrapolate(type.extrapolateRight))\n ) {\n throw new Error(\n `No supported value for \"interpolate\" \\nSupported values: [\"extend\", \"clamp\", \"identity\", Extrapolatation.CLAMP, Extrapolatation.EXTEND, Extrapolatation.IDENTITY]\\n Valid example:\n interpolate(value, [inputRange], [outputRange], {\n extrapolateLeft: Extrapolation.CLAMP,\n extrapolateRight: Extrapolation.IDENTITY\n }})`\n );\n }\n\n Object.assign(extrapolationConfig, type);\n return extrapolationConfig;\n}\n\nfunction internalInterpolate(\n x: number,\n narrowedInput: InterpolationNarrowedInput,\n extrapolationConfig: RequiredExtrapolationConfig\n) {\n \"worklet\";\n const { leftEdgeInput, rightEdgeInput, leftEdgeOutput, rightEdgeOutput } =\n narrowedInput;\n if (rightEdgeInput - leftEdgeInput === 0) {\n return leftEdgeOutput;\n }\n const progress = (x - leftEdgeInput) / (rightEdgeInput - leftEdgeInput);\n const val = leftEdgeOutput + progress * (rightEdgeOutput - leftEdgeOutput);\n const coef = rightEdgeOutput >= leftEdgeOutput ? 1 : -1;\n\n if (coef * val < coef * leftEdgeOutput) {\n return getVal(\n extrapolationConfig.extrapolateLeft,\n coef,\n val,\n leftEdgeOutput,\n rightEdgeOutput,\n x\n );\n } else if (coef * val > coef * rightEdgeOutput) {\n return getVal(\n extrapolationConfig.extrapolateRight,\n coef,\n val,\n leftEdgeOutput,\n rightEdgeOutput,\n x\n );\n }\n\n return val;\n}\n\n// e.g. function interpolate(x, input, output, type = Extrapolatation.CLAMP)\nexport function interpolate(\n x: number,\n input: readonly number[],\n output: readonly number[],\n type?: ExtrapolationType\n): number {\n \"worklet\";\n if (input.length < 2 || output.length < 2) {\n throw Error(\n \"Interpolation input and output should contain at least two values.\"\n );\n }\n\n const extrapolationConfig = validateInterpolationOptions(type);\n const { length } = input;\n const narrowedInput: InterpolationNarrowedInput = {\n leftEdgeInput: input[0],\n rightEdgeInput: input[1],\n leftEdgeOutput: output[0],\n rightEdgeOutput: output[1],\n };\n if (length > 2) {\n if (x > input[length - 1]) {\n narrowedInput.leftEdgeInput = input[length - 2];\n narrowedInput.rightEdgeInput = input[length - 1];\n narrowedInput.leftEdgeOutput = output[length - 2];\n narrowedInput.rightEdgeOutput = output[length - 1];\n } else {\n for (let i = 1; i < length; ++i) {\n if (x <= input[i]) {\n narrowedInput.leftEdgeInput = input[i - 1];\n narrowedInput.rightEdgeInput = input[i];\n narrowedInput.leftEdgeOutput = output[i - 1];\n narrowedInput.rightEdgeOutput = output[i];\n break;\n }\n }\n }\n }\n\n return internalInterpolate(x, narrowedInput, extrapolationConfig);\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -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":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_Platform","require","_Skia","_Data","imgFactory","Skia","Image","MakeImageFromEncoded","bind","useImage","source","onError","useRawData","exports","makeImageFromView","viewRef","callback","Platform","OS","Promise","reject","Error","viewTag","findNodeHandle","current","MakeImageFromViewTag"],"sources":["Image.ts"],"sourcesContent":["import { Platform } from \"../../Platform\";\nimport { Skia } from \"../Skia\";\nimport type { DataSourceParam, SkImage } from \"../types\";\n\nimport { useRawData } from \"./Data\";\n\nconst imgFactory = Skia.Image.MakeImageFromEncoded.bind(Skia.Image);\n\n/**\n * Returns a Skia Image object\n * */\nexport const useImage = (\n source: DataSourceParam,\n onError?: (err: Error) => void\n) => useRawData(source, imgFactory, onError);\n\n/**\n * Creates an image from a given view reference. NOTE: This method has different implementations\n * on web/native. On web, the callback is called with the view ref and the callback is expected to\n * return a promise that resolves to a Skia Image object. On native, the view ref is used to\n * find the view tag and the Skia Image object is created from the view tag. This means that on web\n * you will need to implement the logic to create the image from the view ref yourself.\n * @param viewRef Ref to the view we're creating an image from\n * @returns A promise that resolves to a Skia Image object or rejects\n * with an error id the view tag is invalid.\n */\nexport const makeImageFromView = <\n T extends\n | number\n | React.Component<unknown, unknown>\n | React.ComponentClass<unknown>\n | null,\n>(\n viewRef: React.RefObject<T>,\n callback:\n
|
|
1
|
+
{"version":3,"names":["_Platform","require","_Skia","_Data","imgFactory","Skia","Image","MakeImageFromEncoded","bind","useImage","source","onError","useRawData","exports","makeImageFromView","viewRef","callback","Platform","OS","Promise","reject","Error","viewTag","findNodeHandle","current","MakeImageFromViewTag"],"sources":["Image.ts"],"sourcesContent":["import { Platform } from \"../../Platform\";\nimport { Skia } from \"../Skia\";\nimport type { DataSourceParam, SkImage } from \"../types\";\n\nimport { useRawData } from \"./Data\";\n\nconst imgFactory = Skia.Image.MakeImageFromEncoded.bind(Skia.Image);\n\n/**\n * Returns a Skia Image object\n * */\nexport const useImage = (\n source: DataSourceParam,\n onError?: (err: Error) => void\n) => useRawData(source, imgFactory, onError);\n\n/**\n * Creates an image from a given view reference. NOTE: This method has different implementations\n * on web/native. On web, the callback is called with the view ref and the callback is expected to\n * return a promise that resolves to a Skia Image object. On native, the view ref is used to\n * find the view tag and the Skia Image object is created from the view tag. This means that on web\n * you will need to implement the logic to create the image from the view ref yourself.\n * @param viewRef Ref to the view we're creating an image from\n * @returns A promise that resolves to a Skia Image object or rejects\n * with an error id the view tag is invalid.\n */\nexport const makeImageFromView = <\n T extends\n | number\n | React.Component<unknown, unknown>\n | React.ComponentClass<unknown>\n | null,\n>(\n viewRef: React.RefObject<T>,\n callback:\n null | ((viewRef: React.RefObject<T>) => Promise<SkImage | null>) = null\n) => {\n // In web implementation we just delegate the work to the provided callback\n if (Platform.OS === \"web\") {\n if (callback) {\n return callback(viewRef);\n } else {\n Promise.reject(\n new Error(\n \"Callback is required on web in the makeImageFromView function.\"\n )\n );\n }\n }\n const viewTag = Platform.findNodeHandle(viewRef.current);\n if (viewTag !== null && viewTag !== 0) {\n return Skia.Image.MakeImageFromViewTag(viewTag);\n }\n return Promise.reject(new Error(\"Invalid view tag\"));\n};\n"],"mappings":";;;;;;AAAA,IAAAA,SAAA,GAAAC,OAAA;AACA,IAAAC,KAAA,GAAAD,OAAA;AAGA,IAAAE,KAAA,GAAAF,OAAA;AAEA,MAAMG,UAAU,GAAGC,UAAI,CAACC,KAAK,CAACC,oBAAoB,CAACC,IAAI,CAACH,UAAI,CAACC,KAAK,CAAC;;AAEnE;AACA;AACA;AACO,MAAMG,QAAQ,GAAGA,CACtBC,MAAuB,EACvBC,OAA8B,KAC3B,IAAAC,gBAAU,EAACF,MAAM,EAAEN,UAAU,EAAEO,OAAO,CAAC;;AAE5C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AATAE,OAAA,CAAAJ,QAAA,GAAAA,QAAA;AAUO,MAAMK,iBAAiB,GAAGA,CAO/BC,OAA2B,EAC3BC,QACmE,GAAG,IAAI,KACvE;EACH;EACA,IAAIC,kBAAQ,CAACC,EAAE,KAAK,KAAK,EAAE;IACzB,IAAIF,QAAQ,EAAE;MACZ,OAAOA,QAAQ,CAACD,OAAO,CAAC;IAC1B,CAAC,MAAM;MACLI,OAAO,CAACC,MAAM,CACZ,IAAIC,KAAK,CACP,gEACF,CACF,CAAC;IACH;EACF;EACA,MAAMC,OAAO,GAAGL,kBAAQ,CAACM,cAAc,CAACR,OAAO,CAACS,OAAO,CAAC;EACxD,IAAIF,OAAO,KAAK,IAAI,IAAIA,OAAO,KAAK,CAAC,EAAE;IACrC,OAAOjB,UAAI,CAACC,KAAK,CAACmB,oBAAoB,CAACH,OAAO,CAAC;EACjD;EACA,OAAOH,OAAO,CAACC,MAAM,CAAC,IAAIC,KAAK,CAAC,kBAAkB,CAAC,CAAC;AACtD,CAAC;AAACR,OAAA,CAAAC,iBAAA,GAAAA,iBAAA","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["CanvasKitWebGLBuffer","exports","isNativeBufferAddr","buffer","BigInt","isNativeBufferWeb","HTMLVideoElement","HTMLCanvasElement","ImageBitmap","OffscreenCanvas","VideoFrame","HTMLImageElement","SVGImageElement","isNativeBufferNode","ArrayBuffer"],"sources":["NativeBufferFactory.ts"],"sourcesContent":["import type { SkImage } from \"../Image\";\n\nexport abstract class CanvasKitWebGLBuffer {}\n\nexport type NativeBuffer<\n T extends\n
|
|
1
|
+
{"version":3,"names":["CanvasKitWebGLBuffer","exports","isNativeBufferAddr","buffer","BigInt","isNativeBufferWeb","HTMLVideoElement","HTMLCanvasElement","ImageBitmap","OffscreenCanvas","VideoFrame","HTMLImageElement","SVGImageElement","isNativeBufferNode","ArrayBuffer"],"sources":["NativeBufferFactory.ts"],"sourcesContent":["import type { SkImage } from \"../Image\";\n\nexport abstract class CanvasKitWebGLBuffer {}\n\nexport type NativeBuffer<\n T extends\n bigint | ArrayBuffer | CanvasImageSource | CanvasKitWebGLBuffer | unknown =\n unknown,\n> = T;\n\nexport type NativeBufferAddr = NativeBuffer<bigint>;\nexport type NativeBufferWeb = NativeBuffer<CanvasImageSource>;\nexport type NativeBufferNode = NativeBuffer<ArrayBuffer>;\n\nexport const isNativeBufferAddr = (\n buffer: NativeBuffer\n): buffer is NativeBufferAddr => buffer instanceof BigInt;\nexport const isNativeBufferWeb = (\n buffer: NativeBuffer\n): buffer is NativeBufferWeb =>\n buffer instanceof HTMLVideoElement ||\n buffer instanceof HTMLCanvasElement ||\n buffer instanceof ImageBitmap ||\n buffer instanceof OffscreenCanvas ||\n (typeof VideoFrame !== \"undefined\" && buffer instanceof VideoFrame) ||\n buffer instanceof HTMLImageElement ||\n buffer instanceof SVGImageElement ||\n buffer instanceof CanvasKitWebGLBuffer;\n\nexport const isNativeBufferNode = (\n buffer: NativeBuffer\n): buffer is NativeBufferNode => buffer instanceof ArrayBuffer;\n\nexport interface NativeBufferFactory {\n /**\n * Copy pixels to a native buffer.\n */\n MakeFromImage: (image: SkImage) => NativeBuffer;\n /**\n * Create a native buffer of the given size filled with a procedural test\n * pattern (RGB gradient + diagonal stripes), entirely on the CPU. Useful for\n * examples and tests that need a buffer to feed into\n * `GPUDevice.importExternalTexture` without a camera/video source. Release it\n * with `Release`.\n */\n MakeTestBuffer: (width: number, height: number) => NativeBuffer;\n /**\n * Release a native buffer that was created with `MakeFromImage` or\n * `MakeTestBuffer`.\n */\n Release: (nativeBuffer: NativeBuffer) => void;\n}\n"],"mappings":";;;;;;AAEO,MAAeA,oBAAoB,CAAC;AAAEC,OAAA,CAAAD,oBAAA,GAAAA,oBAAA;AAYtC,MAAME,kBAAkB,GAC7BC,MAAoB,IACWA,MAAM,YAAYC,MAAM;AAACH,OAAA,CAAAC,kBAAA,GAAAA,kBAAA;AACnD,MAAMG,iBAAiB,GAC5BF,MAAoB,IAEpBA,MAAM,YAAYG,gBAAgB,IAClCH,MAAM,YAAYI,iBAAiB,IACnCJ,MAAM,YAAYK,WAAW,IAC7BL,MAAM,YAAYM,eAAe,IAChC,OAAOC,UAAU,KAAK,WAAW,IAAIP,MAAM,YAAYO,UAAW,IACnEP,MAAM,YAAYQ,gBAAgB,IAClCR,MAAM,YAAYS,eAAe,IACjCT,MAAM,YAAYH,oBAAoB;AAACC,OAAA,CAAAI,iBAAA,GAAAA,iBAAA;AAElC,MAAMQ,kBAAkB,GAC7BV,MAAoB,IACWA,MAAM,YAAYW,WAAW;AAACb,OAAA,CAAAY,kBAAA,GAAAA,kBAAA","ignoreList":[]}
|