@shopify/react-native-skia 2.2.19 → 2.2.21

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.
Files changed (53) hide show
  1. package/android/CMakeLists.txt +2 -0
  2. package/apple/SkiaCVPixelBufferUtils.mm +8 -4
  3. package/cpp/api/JsiSkCanvas.h +22 -0
  4. package/cpp/api/JsiSkDispatcher.cpp +9 -0
  5. package/cpp/api/JsiSkDispatcher.h +149 -0
  6. package/cpp/api/JsiSkImage.h +27 -9
  7. package/cpp/api/JsiSkPicture.h +22 -1
  8. package/cpp/api/JsiSkSurface.h +15 -10
  9. package/cpp/api/recorder/Drawings.h +43 -9
  10. package/cpp/api/recorder/JsiRecorder.h +3 -1
  11. package/cpp/api/recorder/RNRecorder.h +10 -4
  12. package/lib/commonjs/external/reanimated/textures.js +31 -28
  13. package/lib/commonjs/external/reanimated/textures.js.map +1 -1
  14. package/lib/commonjs/renderer/Offscreen.js +1 -7
  15. package/lib/commonjs/renderer/Offscreen.js.map +1 -1
  16. package/lib/commonjs/skia/core/SVG.web.d.ts +2 -2
  17. package/lib/commonjs/skia/core/SVG.web.js +23 -7
  18. package/lib/commonjs/skia/core/SVG.web.js.map +1 -1
  19. package/lib/commonjs/skia/web/JsiSkCanvas.d.ts +1 -1
  20. package/lib/commonjs/skia/web/JsiSkCanvas.js +7 -1
  21. package/lib/commonjs/skia/web/JsiSkCanvas.js.map +1 -1
  22. package/lib/commonjs/sksg/Recorder/ReanimatedRecorder.d.ts +4 -0
  23. package/lib/commonjs/sksg/Recorder/ReanimatedRecorder.js +4 -0
  24. package/lib/commonjs/sksg/Recorder/ReanimatedRecorder.js.map +1 -1
  25. package/lib/module/external/reanimated/textures.js +33 -30
  26. package/lib/module/external/reanimated/textures.js.map +1 -1
  27. package/lib/module/renderer/Offscreen.js +1 -8
  28. package/lib/module/renderer/Offscreen.js.map +1 -1
  29. package/lib/module/skia/core/SVG.web.d.ts +2 -2
  30. package/lib/module/skia/core/SVG.web.js +23 -7
  31. package/lib/module/skia/core/SVG.web.js.map +1 -1
  32. package/lib/module/skia/web/JsiSkCanvas.d.ts +1 -1
  33. package/lib/module/skia/web/JsiSkCanvas.js +7 -1
  34. package/lib/module/skia/web/JsiSkCanvas.js.map +1 -1
  35. package/lib/module/sksg/Recorder/ReanimatedRecorder.d.ts +4 -0
  36. package/lib/module/sksg/Recorder/ReanimatedRecorder.js +5 -0
  37. package/lib/module/sksg/Recorder/ReanimatedRecorder.js.map +1 -1
  38. package/lib/typescript/lib/commonjs/skia/core/SVG.web.d.ts +1 -1
  39. package/lib/typescript/lib/commonjs/skia/web/JsiSkCanvas.d.ts +1 -1
  40. package/lib/typescript/lib/commonjs/sksg/Recorder/ReanimatedRecorder.d.ts +4 -0
  41. package/lib/typescript/lib/module/skia/core/SVG.web.d.ts +1 -1
  42. package/lib/typescript/lib/module/skia/web/JsiSkCanvas.d.ts +1 -1
  43. package/lib/typescript/lib/module/sksg/Recorder/ReanimatedRecorder.d.ts +4 -0
  44. package/lib/typescript/src/skia/core/SVG.web.d.ts +2 -2
  45. package/lib/typescript/src/skia/web/JsiSkCanvas.d.ts +1 -1
  46. package/lib/typescript/src/sksg/Recorder/ReanimatedRecorder.d.ts +4 -0
  47. package/package.json +6 -1
  48. package/src/external/reanimated/textures.tsx +36 -27
  49. package/src/renderer/Offscreen.tsx +1 -7
  50. package/src/skia/core/SVG.web.ts +35 -21
  51. package/src/skia/web/JsiSkCanvas.ts +3 -1
  52. package/src/sksg/Recorder/ReanimatedRecorder.ts +4 -0
  53. package/cpp/api/JsiSkThreadSafeDeletion.h +0 -105
@@ -1,32 +1,46 @@
1
+ import { useEffect, useState } from "react";
2
+
1
3
  import { Skia } from "../Skia";
2
- import type { DataSourceParam } from "../types";
4
+ import type { DataSourceParam, SkSVG } from "../types";
3
5
 
4
6
  export const useSVG = (
5
7
  source: DataSourceParam,
6
8
  onError?: (err: Error) => void
7
9
  ) => {
10
+ const [svg, setSVG] = useState<SkSVG | null>(null);
8
11
  if (source === null || source === undefined) {
9
12
  throw new Error(`Invalid svg data source. Got: ${source}`);
10
13
  }
11
- if (
12
- typeof source !== "object" ||
13
- source instanceof Uint8Array ||
14
- !("uri" in source) ||
15
- typeof source.uri !== "string" ||
16
- !("default" in source) ||
17
- typeof source.default !== "string"
18
- ) {
19
- throw new Error(
20
- `Invalid svg data source. Make sure that the source resolves to a string. Got: ${JSON.stringify(
21
- source,
22
- null,
23
- 2
24
- )}`
25
- );
26
- }
27
- const svg = Skia.SVG.MakeFromString(source.default);
28
- if (svg === null && onError !== undefined) {
29
- onError(new Error("Failed to create SVG from source."));
30
- }
14
+ useEffect(() => {
15
+ (async () => {
16
+ let src: string;
17
+ if (typeof source === "string") {
18
+ src = source;
19
+ } else if (
20
+ typeof source === "object" &&
21
+ "default" in source &&
22
+ typeof source.default === "string"
23
+ ) {
24
+ src = source.default;
25
+ } else if (typeof source === "object" && "uri" in source) {
26
+ src = source.uri;
27
+ } else {
28
+ throw new Error(
29
+ `Invalid svg data source. Make sure that the source resolves to a string. Got: ${JSON.stringify(
30
+ source,
31
+ null,
32
+ 2
33
+ )}`
34
+ );
35
+ }
36
+ const result = await fetch(src);
37
+ const svgStr = await result.text();
38
+ const newSvg = Skia.SVG.MakeFromString(svgStr);
39
+ setSVG(newSvg);
40
+ if (newSvg === null && onError !== undefined) {
41
+ onError(new Error("Failed to create SVG from source."));
42
+ }
43
+ })();
44
+ }, [onError, source]);
31
45
  return svg;
32
46
  };
@@ -305,7 +305,9 @@ export class JsiSkCanvas
305
305
  );
306
306
  }
307
307
 
308
- drawSvg(svg: SkSVG, _width?: number, _height?: number) {
308
+ drawSvg(svg: SkSVG, width?: number, height?: number) {
309
+ const ctm = this.ref.getLocalToDevice();
310
+ console.log({ ctm, width, height });
309
311
  const image = this.CanvasKit.MakeImageFromCanvasImageSource(
310
312
  (svg as JsiSkSVG).ref
311
313
  );
@@ -32,6 +32,10 @@ import type {
32
32
  import type { AnimatedProps } from "../../renderer";
33
33
  import { isSharedValue } from "../utils";
34
34
 
35
+ /**
36
+ * Currently the recorder only work if the GPU resources (e.g Images) are owned by the main thread.
37
+ * It will crash otherwise on Ganesh (iOS/Android).
38
+ */
35
39
  export class ReanimatedRecorder implements BaseRecorder {
36
40
  private values = new Set<SharedValue<unknown>>();
37
41
  private recorder: JsiRecorder;
@@ -1,105 +0,0 @@
1
- #pragma once
2
-
3
- #include <functional>
4
- #include <memory>
5
- #include <mutex>
6
- #include <queue>
7
- #include <thread>
8
-
9
- // Define this to disable thread-safe deletion (for testing purposes)
10
- // #define DISABLE_THREAD_SAFE_DELETION
11
-
12
- namespace RNSkia {
13
-
14
- /**
15
- * Utility class for managing thread-safe deletion of Skia objects.
16
- * Ensures objects are deleted on the thread that created them.
17
- */
18
- template <typename T> class ThreadSafeDeletion {
19
- private:
20
- struct DeletionItem {
21
- sk_sp<T> object;
22
- std::thread::id creationThreadId;
23
- };
24
-
25
- static inline std::mutex _queueMutex;
26
- static inline std::queue<DeletionItem> _deletionQueue;
27
-
28
- std::thread::id _creationThreadId;
29
-
30
- public:
31
- ThreadSafeDeletion() : _creationThreadId(std::this_thread::get_id()) {}
32
-
33
- /**
34
- * Handles deletion of the object. If we're on the wrong thread,
35
- * queues it for later deletion. Otherwise, allows immediate deletion.
36
- * The object is always considered handled after this call.
37
- */
38
- void handleDeletion(sk_sp<T> object) {
39
- if (!object) {
40
- return;
41
- }
42
-
43
- #ifdef DISABLE_THREAD_SAFE_DELETION
44
- // When disabled, allow immediate deletion
45
- // This will likely cause crashes when objects are deleted on wrong thread
46
- return;
47
- #else
48
- // Always try to drain the queue when handling deletions
49
- drainDeletionQueue();
50
-
51
- // Check if we're on the creation thread
52
- if (std::this_thread::get_id() != _creationThreadId) {
53
- // Queue for deletion on the correct thread
54
- std::lock_guard<std::mutex> lock(_queueMutex);
55
- _deletionQueue.push({object, _creationThreadId});
56
- return;
57
- }
58
-
59
- // We're on the correct thread, allow immediate deletion via destructor
60
- return;
61
- #endif
62
- }
63
-
64
- /**
65
- * Drains the deletion queue for objects created on the current thread.
66
- * Should be called periodically (e.g., when creating new objects).
67
- */
68
- static void drainDeletionQueue() {
69
- #ifndef DISABLE_THREAD_SAFE_DELETION
70
- auto currentThreadId = std::this_thread::get_id();
71
- std::queue<DeletionItem> remainingItems;
72
-
73
- std::lock_guard<std::mutex> lock(_queueMutex);
74
-
75
- // Process all items in the queue
76
- while (!_deletionQueue.empty()) {
77
- auto item = _deletionQueue.front();
78
- _deletionQueue.pop();
79
-
80
- // If this item belongs to the current thread, let it be deleted
81
- if (item.creationThreadId == currentThreadId) {
82
- // The sk_sp destructor will handle the cleanup
83
- // Just let it go out of scope
84
- } else {
85
- // Keep items that belong to other threads
86
- remainingItems.push(item);
87
- }
88
- }
89
-
90
- // Put back items that couldn't be deleted
91
- _deletionQueue = std::move(remainingItems);
92
- #endif
93
- }
94
-
95
- /**
96
- * Returns the number of items waiting for deletion.
97
- * Useful for debugging and testing.
98
- */
99
- static size_t getPendingDeletionCount() {
100
- std::lock_guard<std::mutex> lock(_queueMutex);
101
- return _deletionQueue.size();
102
- }
103
- };
104
-
105
- } // namespace RNSkia