@shopify/react-native-skia 2.12.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.
Files changed (130) hide show
  1. package/LICENSE.md +2 -1
  2. package/Package.swift +4 -4
  3. package/android/CMakeLists.txt +22 -177
  4. package/android/build.gradle +40 -209
  5. package/android/cpp/jni/JniSkiaManager.cpp +3 -45
  6. package/android/cpp/jni/include/JniPlatformContext.h +1 -1
  7. package/android/cpp/jni/include/JniSkiaBaseView.h +18 -11
  8. package/android/cpp/jni/include/JniSkiaManager.h +3 -4
  9. package/android/cpp/jni/include/JniSkiaPictureView.h +5 -5
  10. package/android/cpp/rnskia-android/OpenGLContext.h +1 -1
  11. package/android/cpp/rnskia-android/RNSkAndroidView.h +6 -6
  12. package/android/cpp/rnskia-android/RNSkOpenGLCanvasProvider.cpp +4 -4
  13. package/android/cpp/rnskia-android/RNSkOpenGLCanvasProvider.h +2 -2
  14. package/android/cpp/rnskia-android/gl/Surface.h +1 -1
  15. package/android/src/main/AndroidManifest.xml +1 -1
  16. package/android/src/main/java/com/{shopify/reactnative → reactnative}/skia/PlatformContext.java +1 -1
  17. package/android/src/main/java/com/{shopify/reactnative → reactnative}/skia/RNSkVideo.java +1 -1
  18. package/android/src/main/java/com/{shopify/reactnative → reactnative}/skia/RNSkiaModule.java +1 -8
  19. package/android/src/main/java/com/reactnative/skia/RNSkiaPackage.java +57 -0
  20. package/android/src/main/java/com/reactnative/skia/SkiaBaseView.java +185 -0
  21. package/android/src/main/java/com/{shopify/reactnative → reactnative}/skia/SkiaBaseViewManager.java +20 -1
  22. package/android/src/main/java/com/{shopify/reactnative → reactnative}/skia/SkiaManager.java +11 -6
  23. package/android/src/main/java/com/{shopify/reactnative → reactnative}/skia/SkiaPictureView.java +3 -3
  24. package/android/src/main/java/com/{shopify/reactnative → reactnative}/skia/SkiaPictureViewManager.java +1 -1
  25. package/android/src/main/java/com/{shopify/reactnative → reactnative}/skia/SkiaSurfaceView.java +13 -3
  26. package/android/src/main/java/com/{shopify/reactnative → reactnative}/skia/SkiaTextureView.java +5 -3
  27. package/android/src/main/java/com/{shopify/reactnative → reactnative}/skia/SkiaViewAPI.java +1 -1
  28. package/android/src/main/java/com/{shopify/reactnative → reactnative}/skia/ViewScreenshotService.java +1 -1
  29. package/apple/MetalContext.mm +1 -1
  30. package/apple/RNSkiaModule.h +1 -10
  31. package/apple/RNSkiaModule.mm +2 -10
  32. package/apple/SkiaManager.h +0 -2
  33. package/apple/SkiaManager.mm +4 -6
  34. package/apple/SkiaPictureView.h +2 -2
  35. package/apple/SkiaPictureView.mm +0 -4
  36. package/apple/SkiaUIView.h +3 -18
  37. package/apple/SkiaUIView.mm +0 -30
  38. package/cpp/api/CustomBlendModes.h +17 -0
  39. package/cpp/api/JsiSkCanvas.h +19 -10
  40. package/cpp/api/JsiSkImage.h +1 -1
  41. package/cpp/api/JsiSkImageFilter.h +3 -1
  42. package/cpp/api/JsiSkParagraph.h +2 -1
  43. package/cpp/api/JsiSkParagraphBuilder.h +1 -1
  44. package/cpp/api/JsiSkParagraphBuilderFactory.h +1 -1
  45. package/cpp/api/JsiSkPath.h +11 -4
  46. package/cpp/api/JsiSkPathBuilder.h +11 -4
  47. package/cpp/api/JsiSkPictureRecorder.h +2 -1
  48. package/cpp/api/JsiSkShader.h +3 -1
  49. package/cpp/api/JsiSkSkottie.h +27 -25
  50. package/cpp/api/recorder/Command.h +1 -1
  51. package/cpp/api/recorder/Convertor.h +1 -1
  52. package/cpp/api/recorder/DataTypes.h +1 -1
  53. package/cpp/api/recorder/DrawingCtx.h +1 -1
  54. package/cpp/api/recorder/JsiRecorder.h +7 -4
  55. package/cpp/api/third_party/base64.cpp +1 -1
  56. package/cpp/jsi/JSICache.cpp +23 -0
  57. package/cpp/jsi/JSICache.h +28 -1
  58. package/cpp/jsi/NativeObject.h +36 -7
  59. package/cpp/jsi/ViewProperty.h +0 -4
  60. package/cpp/rnskia/RNDawnContext.h +1 -1
  61. package/lib/commonjs/animation/functions/interpolatePaths.js +18 -0
  62. package/lib/commonjs/animation/functions/interpolatePaths.js.map +1 -1
  63. package/lib/commonjs/mock/index.js +0 -1
  64. package/lib/commonjs/mock/index.js.map +1 -1
  65. package/lib/commonjs/renderer/Canvas.d.ts +11 -3
  66. package/lib/commonjs/renderer/Canvas.js +8 -6
  67. package/lib/commonjs/renderer/Canvas.js.map +1 -1
  68. package/lib/commonjs/skia/web/JsiSkCanvas.js +9 -4
  69. package/lib/commonjs/skia/web/JsiSkCanvas.js.map +1 -1
  70. package/lib/commonjs/specs/SkiaPictureViewNativeComponent.d.ts +2 -0
  71. package/lib/commonjs/specs/SkiaPictureViewNativeComponent.js.map +1 -1
  72. package/lib/commonjs/specs/SkiaPictureViewNativeComponent.web.d.ts +3 -1
  73. package/lib/commonjs/specs/SkiaPictureViewNativeComponent.web.js +3 -0
  74. package/lib/commonjs/specs/SkiaPictureViewNativeComponent.web.js.map +1 -1
  75. package/lib/commonjs/views/SkiaPictureView.js +2 -12
  76. package/lib/commonjs/views/SkiaPictureView.js.map +1 -1
  77. package/lib/commonjs/views/types.d.ts +19 -8
  78. package/lib/commonjs/views/types.js.map +1 -1
  79. package/lib/module/animation/functions/interpolatePaths.js +18 -0
  80. package/lib/module/animation/functions/interpolatePaths.js.map +1 -1
  81. package/lib/module/mock/index.js +0 -1
  82. package/lib/module/mock/index.js.map +1 -1
  83. package/lib/module/renderer/Canvas.d.ts +11 -3
  84. package/lib/module/renderer/Canvas.js +7 -5
  85. package/lib/module/renderer/Canvas.js.map +1 -1
  86. package/lib/module/skia/web/JsiSkCanvas.js +9 -4
  87. package/lib/module/skia/web/JsiSkCanvas.js.map +1 -1
  88. package/lib/module/specs/SkiaPictureViewNativeComponent.d.ts +2 -0
  89. package/lib/module/specs/SkiaPictureViewNativeComponent.js.map +1 -1
  90. package/lib/module/specs/SkiaPictureViewNativeComponent.web.d.ts +3 -1
  91. package/lib/module/specs/SkiaPictureViewNativeComponent.web.js +3 -0
  92. package/lib/module/specs/SkiaPictureViewNativeComponent.web.js.map +1 -1
  93. package/lib/module/views/SkiaPictureView.js +2 -12
  94. package/lib/module/views/SkiaPictureView.js.map +1 -1
  95. package/lib/module/views/types.d.ts +19 -8
  96. package/lib/module/views/types.js.map +1 -1
  97. package/lib/typescript/lib/commonjs/mock/index.d.ts +0 -1
  98. package/lib/typescript/lib/commonjs/renderer/Canvas.d.ts +2 -2
  99. package/lib/typescript/lib/commonjs/specs/SkiaPictureViewNativeComponent.web.d.ts +3 -1
  100. package/lib/typescript/lib/module/mock/index.d.ts +0 -1
  101. package/lib/typescript/lib/module/renderer/Canvas.d.ts +2 -2
  102. package/lib/typescript/lib/module/specs/SkiaPictureViewNativeComponent.web.d.ts +3 -1
  103. package/lib/typescript/src/renderer/Canvas.d.ts +11 -3
  104. package/lib/typescript/src/specs/SkiaPictureViewNativeComponent.d.ts +2 -0
  105. package/lib/typescript/src/specs/SkiaPictureViewNativeComponent.web.d.ts +3 -1
  106. package/lib/typescript/src/views/types.d.ts +19 -8
  107. package/package.json +3 -3
  108. package/react-native-skia.podspec +4 -10
  109. package/src/animation/functions/interpolatePaths.ts +24 -0
  110. package/src/mock/index.ts +0 -1
  111. package/src/renderer/Canvas.tsx +23 -5
  112. package/src/skia/web/JsiSkCanvas.ts +14 -9
  113. package/src/specs/SkiaPictureViewNativeComponent.ts +5 -0
  114. package/src/specs/SkiaPictureViewNativeComponent.web.ts +5 -0
  115. package/src/views/SkiaPictureView.tsx +2 -10
  116. package/src/views/types.ts +23 -10
  117. package/android/src/latest/java/com/shopify/reactnative/skia/ReactNativeCompatible.java +0 -11
  118. package/android/src/main/java/com/shopify/reactnative/skia/RNSkiaPackage.java +0 -79
  119. package/android/src/main/java/com/shopify/reactnative/skia/SkiaAHBView.java +0 -113
  120. package/android/src/main/java/com/shopify/reactnative/skia/SkiaBaseView.java +0 -136
  121. package/android/src/paper/java/com/facebook/react/viewmanagers/SkiaPictureViewManagerDelegate.java +0 -41
  122. package/android/src/paper/java/com/facebook/react/viewmanagers/SkiaPictureViewManagerInterface.java +0 -20
  123. package/android/src/paper/java/com/facebook/react/viewmanagers/SkiaWebGPUViewManagerDelegate.java +0 -35
  124. package/android/src/paper/java/com/facebook/react/viewmanagers/SkiaWebGPUViewManagerInterface.java +0 -17
  125. package/android/src/paper/java/com/shopify/reactnative/skia/NativeSkiaModuleSpec.java +0 -38
  126. package/android/src/reactnative74/java/com/shopify/reactnative/skia/ReactNativeCompatible.java +0 -14
  127. package/apple/SkiaPictureViewManager.h +0 -8
  128. package/apple/SkiaPictureViewManager.mm +0 -60
  129. package/apple/SkiaWebGPUView.h +0 -20
  130. package/apple/WebGPUMetalView.h +0 -12
@@ -1,4 +1,4 @@
1
- package com.shopify.reactnative.skia;
1
+ package com.reactnative.skia;
2
2
 
3
3
  import android.annotation.SuppressLint;
4
4
  import android.content.Context;
@@ -16,11 +16,13 @@ public class SkiaTextureView extends TextureView implements TextureView.SurfaceT
16
16
  SkiaViewAPI mApi;
17
17
  boolean mDebug;
18
18
 
19
- public SkiaTextureView(Context context, SkiaViewAPI api, boolean debug) {
19
+ public SkiaTextureView(Context context, SkiaViewAPI api, boolean debug, boolean opaque) {
20
20
  super(context);
21
21
  mApi = api;
22
22
  mDebug = debug;
23
- setOpaque(false);
23
+ // An opaque TextureView lets the UI toolkit skip blending it; it can be
24
+ // toggled on a live view.
25
+ setOpaque(opaque);
24
26
  setSurfaceTextureListener(this);
25
27
  }
26
28
 
@@ -1,4 +1,4 @@
1
- package com.shopify.reactnative.skia;
1
+ package com.reactnative.skia;
2
2
 
3
3
  import android.graphics.SurfaceTexture;
4
4
  import android.view.Surface;
@@ -1,4 +1,4 @@
1
- package com.shopify.reactnative.skia;
1
+ package com.reactnative.skia;
2
2
 
3
3
  import android.graphics.Bitmap;
4
4
  import android.graphics.Canvas;
@@ -31,7 +31,7 @@ MetalContext::MetalContext() {
31
31
  GrContextOptions grContextOptions; // set different options here.
32
32
 
33
33
  // Create the Skia Direct Context
34
- _directContext = GrDirectContexts::MakeMetal(backendContext);
34
+ _directContext = GrDirectContexts::MakeMetal(backendContext, grContextOptions);
35
35
  if (_directContext == nullptr) {
36
36
  RNSkia::RNSkLogger::logToConsole("Couldn't create a Skia Metal Context");
37
37
  }
@@ -1,19 +1,10 @@
1
1
  #pragma once
2
2
 
3
- #ifdef RCT_NEW_ARCH_ENABLED
4
3
  #import <rnskia/rnskia.h>
5
- #else
6
- #import <React/RCTBridgeModule.h>
7
- #endif
8
4
 
9
5
  #include "SkiaManager.h"
10
6
 
11
- @interface RNSkiaModule : NSObject
12
- #ifdef RCT_NEW_ARCH_ENABLED
13
- <NativeSkiaModuleSpec>
14
- #else
15
- <RCTBridgeModule>
16
- #endif
7
+ @interface RNSkiaModule : NSObject <NativeSkiaModuleSpec>
17
8
 
18
9
  - (SkiaManager *)manager;
19
10
 
@@ -1,6 +1,5 @@
1
1
 
2
2
  #import "RNSkiaModule.h"
3
- #import <React/RCTBridge+Private.h>
4
3
  #import <ReactCommon/RCTTurboModule.h>
5
4
 
6
5
  @implementation RNSkiaModule {
@@ -35,14 +34,9 @@ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(install) {
35
34
  // Already initialized, ignore call.
36
35
  return @true;
37
36
  }
38
- #ifndef RCT_REMOVE_LEGACY_ARCH
39
37
  if (!jsInvoker) {
40
- RCTCxxBridge *cxxBridge = (RCTCxxBridge *)self.bridge;
41
- jsInvoker = cxxBridge.jsCallInvoker;
42
- }
43
- #endif
44
- if (!jsInvoker) {
45
- NSLog(@"[RNSkiaModule] Failed to install SkiaManager: jsInvoker is not initialized.");
38
+ NSLog(@"[RNSkiaModule] Failed to install SkiaManager: jsInvoker is not "
39
+ @"initialized.");
46
40
  return @false;
47
41
  }
48
42
  skiaManager = [[SkiaManager alloc] initWithBridge:self.bridge
@@ -50,12 +44,10 @@ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(install) {
50
44
  return @true;
51
45
  }
52
46
 
53
- #ifdef RCT_NEW_ARCH_ENABLED
54
47
  - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
55
48
  (const facebook::react::ObjCTurboModule::InitParams &)params {
56
49
  jsInvoker = params.jsInvoker;
57
50
  return std::make_shared<facebook::react::NativeSkiaModuleSpecJSI>(params);
58
51
  }
59
- #endif
60
52
 
61
53
  @end
@@ -16,10 +16,8 @@
16
16
  jsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)
17
17
  jsInvoker;
18
18
 
19
- #ifdef RCT_NEW_ARCH_ENABLED
20
19
  // Fabric components do not have a better way to interact with TurboModules.
21
20
  // Workaround to get the SkManager instance from singleton.
22
21
  + (std::shared_ptr<RNSkia::RNSkManager>)latestActiveSkManager;
23
- #endif // RCT_NEW_ARCH_ENABLED
24
22
 
25
23
  @end
@@ -7,10 +7,9 @@
7
7
 
8
8
  #import "RNSkApplePlatformContext.h"
9
9
 
10
- // Forward-declared runtime accessor that is satisfied by RCTCxxBridge
11
- // (legacy/transitional) and RCTBridgeProxy (bridgeless). Avoids referencing
12
- // RCTCxxBridge directly, which is compiled out when RCT_REMOVE_LEGACY_ARCH
13
- // is set (React Native 0.82+).
10
+ // Forward-declared runtime accessor satisfied by RCTBridgeProxy (bridgeless).
11
+ // Avoids referencing RCTCxxBridge, which is compiled out when
12
+ // RCT_REMOVE_LEGACY_ARCH is set (React Native 0.82+).
14
13
  @interface RCTBridge (RNSkiaRuntime)
15
14
  - (void *)runtime;
16
15
  @end
@@ -54,12 +53,11 @@ static __weak SkiaManager *sharedInstance = nil;
54
53
  sharedInstance = nil;
55
54
  }
56
55
 
57
- #ifdef RCT_NEW_ARCH_ENABLED
58
56
  + (std::shared_ptr<RNSkia::RNSkManager>)latestActiveSkManager {
59
57
  if (sharedInstance != nil) {
60
58
  return [sharedInstance skManager];
61
59
  }
62
60
  return nullptr;
63
61
  }
64
- #endif // RCT_NEW_ARCH_ENABLED
62
+
65
63
  @end
@@ -1,7 +1,7 @@
1
- #ifdef RCT_NEW_ARCH_ENABLED
1
+ #pragma once
2
+
2
3
  #import "SkiaUIView.h"
3
4
 
4
5
  @interface SkiaPictureView : SkiaUIView
5
6
 
6
7
  @end
7
- #endif // RCT_NEW_ARCH_ENABLED
@@ -1,4 +1,3 @@
1
- #ifdef RCT_NEW_ARCH_ENABLED
2
1
  #import "SkiaPictureView.h"
3
2
 
4
3
  #import "RNSkAppleView.h"
@@ -9,7 +8,6 @@
9
8
  #import "SkiaManager.h"
10
9
  #import "SkiaUIView.h"
11
10
 
12
- #import <React/RCTBridge+Private.h>
13
11
  #import <React/RCTConversions.h>
14
12
  #import <React/RCTFabricComponentsPlugins.h>
15
13
 
@@ -70,5 +68,3 @@ using namespace facebook::react;
70
68
  Class<RCTComponentViewProtocol> SkiaPictureViewCls(void) {
71
69
  return SkiaPictureView.class;
72
70
  }
73
-
74
- #endif // RCT_NEW_ARCH_ENABLED
@@ -10,29 +10,14 @@
10
10
  #import <React/RCTUIKit.h>
11
11
  #endif // !TARGET_OS_OSX
12
12
 
13
+ #import <React/RCTViewComponentView.h>
14
+
13
15
  #import "RNSkAppleView.h"
14
16
  #import "RNSkManager.h"
15
17
  #import "SkiaManager.h"
16
18
 
17
- #if RCT_NEW_ARCH_ENABLED
18
- #import <React/RCTViewComponentView.h>
19
- #endif // RCT_NEW_ARCH_ENABLED
20
-
21
- @interface SkiaUIView :
22
- #if RCT_NEW_ARCH_ENABLED
23
- RCTViewComponentView
24
- #else
25
- #if !TARGET_OS_OSX
26
- UIView
27
- #else
28
- RCTUIView
29
- #endif // !TARGET_OS_OSX
30
- #endif // RCT_NEW_ARCH_ENABLED
19
+ @interface SkiaUIView : RCTViewComponentView
31
20
 
32
- - (instancetype)
33
- initWithManager:(RNSkia::RNSkManager *)manager
34
- factory:(std::function<std::shared_ptr<RNSkBaseAppleView>(
35
- std::shared_ptr<RNSkia::RNSkPlatformContext>)>)factory;
36
21
  - (void)initCommon:(RNSkia::RNSkManager *)manager
37
22
  factory:(std::function<std::shared_ptr<RNSkBaseAppleView>(
38
23
  std::shared_ptr<RNSkia::RNSkPlatformContext>)>)factory;
@@ -1,5 +1,4 @@
1
1
  #import <QuartzCore/CATransaction.h>
2
- #import <React/RCTBridge.h>
3
2
 
4
3
  #import "RNSkiaModule.h"
5
4
  #import "SkiaUIView.h"
@@ -24,24 +23,6 @@
24
23
 
25
24
  #pragma mark Initialization and destruction
26
25
 
27
- - (instancetype)initWithManager:(RNSkia::RNSkManager *)manager
28
- factory:
29
- (std::function<std::shared_ptr<RNSkBaseAppleView>(
30
- std::shared_ptr<RNSkia::RNSkPlatformContext>)>)
31
- factory {
32
- self = [super init];
33
- if (self) {
34
- [self initCommon:manager factory:factory];
35
- }
36
- // Listen to notifications about module invalidation
37
- [[NSNotificationCenter defaultCenter]
38
- addObserver:self
39
- selector:@selector(willInvalidateModules)
40
- name:RCTBridgeWillInvalidateModulesNotification
41
- object:nil];
42
- return self;
43
- }
44
-
45
26
  - (void)initCommon:(RNSkia::RNSkManager *)manager
46
27
  factory:(std::function<std::shared_ptr<RNSkBaseAppleView>(
47
28
  std::shared_ptr<RNSkia::RNSkPlatformContext>)>)factory {
@@ -51,11 +32,6 @@
51
32
  _factory = factory;
52
33
  }
53
34
 
54
- - (void)willInvalidateModules {
55
- _impl = nullptr;
56
- _manager = nullptr;
57
- }
58
-
59
35
  #pragma mark Lifecycle
60
36
 
61
37
  #if !TARGET_OS_OSX
@@ -99,13 +75,8 @@
99
75
 
100
76
  - (void)dealloc {
101
77
  [self unregisterView];
102
- [[NSNotificationCenter defaultCenter]
103
- removeObserver:self
104
- name:RCTBridgeWillInvalidateModulesNotification
105
- object:nil];
106
78
  }
107
79
 
108
- #ifdef RCT_NEW_ARCH_ENABLED
109
80
  - (void)prepareForRecycle {
110
81
  [super prepareForRecycle];
111
82
  [self unregisterView];
@@ -120,7 +91,6 @@
120
91
  _manager = [SkiaManager latestActiveSkManager].get();
121
92
  }
122
93
  }
123
- #endif // RCT_NEW_ARCH_ENABLED
124
94
 
125
95
  - (void)unregisterView {
126
96
  if (_manager != nullptr && _nativeId != 0) {
@@ -1,5 +1,8 @@
1
1
  #pragma once
2
2
 
3
+ #include <stdexcept>
4
+ #include <string>
5
+
3
6
  #include "include/core/SkBlender.h"
4
7
  #include "include/core/SkPaint.h"
5
8
  #include "include/core/SkString.h"
@@ -94,4 +97,18 @@ inline void applyBlendMode(SkPaint &paint, int blendModeValue) {
94
97
  }
95
98
  }
96
99
 
100
+ // Converts a JS blend mode value to an SkBlendMode for the Skia entry points
101
+ // that take a plain SkBlendMode rather than a paint (drawPatch, drawVertices,
102
+ // drawAtlas, drawColor). The custom blend modes above are implemented as
103
+ // blenders on an SkPaint and have no SkBlendMode equivalent, so they - and any
104
+ // other out of range value - are rejected instead of being cast blindly.
105
+ inline SkBlendMode toBlendMode(double blendModeValue) {
106
+ auto value = static_cast<int>(blendModeValue);
107
+ if (value < 0 || value > static_cast<int>(SkBlendMode::kLastMode)) {
108
+ throw std::invalid_argument("Unsupported blend mode: " +
109
+ std::to_string(value));
110
+ }
111
+ return static_cast<SkBlendMode>(value);
112
+ }
113
+
97
114
  } // namespace RNSkia
@@ -5,6 +5,7 @@
5
5
  #include <utility>
6
6
  #include <vector>
7
7
 
8
+ #include "CustomBlendModes.h"
8
9
  #include "JsiSkConverters.h"
9
10
  #include "JsiSkFont.h"
10
11
  #include "JsiSkImage.h"
@@ -226,8 +227,7 @@ public:
226
227
 
227
228
  void drawVertices(sk_sp<SkVertices> vertices, double blendMode,
228
229
  std::shared_ptr<SkPaint> paint) {
229
- _canvas->drawVertices(vertices, static_cast<SkBlendMode>(blendMode),
230
- *paint);
230
+ _canvas->drawVertices(vertices, toBlendMode(blendMode), *paint);
231
231
  }
232
232
 
233
233
  JSI_HOST_FUNCTION(drawPatch) {
@@ -287,11 +287,19 @@ public:
287
287
  }
288
288
  }
289
289
 
290
- auto paint =
291
- count >= 4 ? JsiSkPaint::fromValue(runtime, arguments[4]) : nullptr;
292
- auto blendMode = static_cast<SkBlendMode>(arguments[3].asNumber());
290
+ auto blendMode =
291
+ count >= 4 && !arguments[3].isNull() && !arguments[3].isUndefined()
292
+ ? toBlendMode(arguments[3].asNumber())
293
+ : SkBlendMode::kModulate;
294
+
295
+ std::shared_ptr<SkPaint> paint;
296
+ if (count >= 5 && !arguments[4].isNull() && !arguments[4].isUndefined()) {
297
+ paint = JsiSkPaint::fromValue(runtime, arguments[4]);
298
+ }
299
+ SkPaint defaultPaint;
293
300
  _canvas->drawPatch(cubics.data(), colors.empty() ? nullptr : colors.data(),
294
- texs.empty() ? nullptr : texs.data(), blendMode, *paint);
301
+ texs.empty() ? nullptr : texs.data(), blendMode,
302
+ paint ? *paint : defaultPaint);
295
303
  return jsi::Value::undefined();
296
304
  }
297
305
 
@@ -392,7 +400,7 @@ public:
392
400
 
393
401
  void drawColor(JsiColor cl, JsiOptional<double> mode) {
394
402
  if (mode.has_value()) {
395
- _canvas->drawColor(cl, static_cast<SkBlendMode>(*mode));
403
+ _canvas->drawColor(cl, toBlendMode(*mode));
396
404
  } else {
397
405
  _canvas->drawColor(cl);
398
406
  }
@@ -411,9 +419,10 @@ public:
411
419
  auto rects = arguments[1].asObject(runtime).asArray(runtime);
412
420
  auto transforms = arguments[2].asObject(runtime).asArray(runtime);
413
421
  auto paint = JsiSkPaint::fromValue(runtime, arguments[3]);
414
- auto blendMode = count > 5 && !arguments[4].isUndefined()
415
- ? static_cast<SkBlendMode>(arguments[4].asNumber())
416
- : SkBlendMode::kDstOver;
422
+ auto blendMode =
423
+ count > 4 && !arguments[4].isNull() && !arguments[4].isUndefined()
424
+ ? toBlendMode(arguments[4].asNumber())
425
+ : SkBlendMode::kDstOver;
417
426
 
418
427
  std::vector<SkRSXform> xforms;
419
428
  int xformsSize = static_cast<int>(transforms.size(runtime));
@@ -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 = (size_t)CFDataGetLength(cfICC);
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
- size_t getMemoryPressure() override { return 1024 * 1024; }
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);
@@ -277,7 +277,8 @@ public:
277
277
  &JsiSkParagraph::extendedVisit);
278
278
  }
279
279
 
280
- size_t getMemoryPressure() override { return 1024 * 1024; }
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 1024 * 1024; }
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 1024 * 1024; }
50
+ size_t getMemoryPressure() override { return kMinMemoryPressure; }
51
51
 
52
52
  explicit JsiSkParagraphBuilderFactory(
53
53
  std::shared_ptr<RNSkPlatformContext> context)
@@ -640,11 +640,18 @@ public:
640
640
  : JsiSkPath(std::move(context), SkPathBuilder(path)) {}
641
641
 
642
642
  size_t getMemoryPressure() override {
643
- auto builder = getObject();
644
- if (!builder)
643
+ if (isDisposed()) {
645
644
  return 0;
646
-
647
- return builder->snapshot().approximateBytesUsed();
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
- auto builder = getObject();
275
- if (!builder)
274
+ if (isDisposed()) {
276
275
  return 0;
277
- // Estimate memory usage based on snapshot
278
- return builder->snapshot().approximateBytesUsed();
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
- size_t getMemoryPressure() override { return 1024 * 1024; }
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) {
@@ -29,7 +29,9 @@ public:
29
29
  : JsiSkWrappingSkPtrNativeObject<JsiSkShader, SkShader>(
30
30
  std::move(context), std::move(shader)) {}
31
31
 
32
- size_t getMemoryPressure() override { return 1024 * 1024; }
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) {
@@ -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
- using namespace facebook;
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 || !animation->_animation) {
583
- return 1024; // Base size if no animation
602
+ if (!animation) {
603
+ return kMinMemoryPressure;
584
604
  }
585
-
586
- auto size = animation->_animation->size();
587
- auto duration = animation->_animation->duration();
588
- auto fps = animation->_animation->fps();
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
@@ -55,7 +55,7 @@ public:
55
55
  CommandType type;
56
56
  std::string nodeType;
57
57
 
58
- Command(CommandType t) : type(t) {}
58
+ explicit Command(CommandType t) : type(t) {}
59
59
  Command(CommandType t, std::string nodeT) : type(t), nodeType(nodeT) {}
60
60
  virtual ~Command() = default;
61
61
  };
@@ -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
 
@@ -78,7 +78,7 @@ SkPoint processPoint(jsi::Runtime &runtime, const jsi::Value &value) {
78
78
  }
79
79
  }
80
80
  throw std::runtime_error("Couldn't read point value");
81
- };
81
+ }
82
82
 
83
83
  // TODO: return the SkRRect directly
84
84
  std::shared_ptr<SkRRect> processRRect(jsi::Runtime &runtime,
@@ -52,7 +52,7 @@ struct Composers {
52
52
 
53
53
  class DrawingCtx {
54
54
  public:
55
- DrawingCtx(SkCanvas *canvas) : canvas(canvas) {
55
+ explicit DrawingCtx(SkCanvas *canvas) : canvas(canvas) {
56
56
  SkPaint paint;
57
57
  paint.setAntiAlias(true);
58
58
  paints.push_back(paint);