@shopify/react-native-skia 2.12.0 → 2.13.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.
Files changed (103) 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/RNSkAndroidView.h +6 -6
  11. package/android/cpp/rnskia-android/RNSkOpenGLCanvasProvider.cpp +4 -4
  12. package/android/cpp/rnskia-android/RNSkOpenGLCanvasProvider.h +2 -2
  13. package/android/src/main/AndroidManifest.xml +1 -1
  14. package/android/src/main/java/com/{shopify/reactnative → reactnative}/skia/PlatformContext.java +1 -1
  15. package/android/src/main/java/com/{shopify/reactnative → reactnative}/skia/RNSkVideo.java +1 -1
  16. package/android/src/main/java/com/{shopify/reactnative → reactnative}/skia/RNSkiaModule.java +1 -8
  17. package/android/src/main/java/com/reactnative/skia/RNSkiaPackage.java +57 -0
  18. package/android/src/main/java/com/reactnative/skia/SkiaBaseView.java +185 -0
  19. package/android/src/main/java/com/{shopify/reactnative → reactnative}/skia/SkiaBaseViewManager.java +20 -1
  20. package/android/src/main/java/com/{shopify/reactnative → reactnative}/skia/SkiaManager.java +11 -6
  21. package/android/src/main/java/com/{shopify/reactnative → reactnative}/skia/SkiaPictureView.java +3 -3
  22. package/android/src/main/java/com/{shopify/reactnative → reactnative}/skia/SkiaPictureViewManager.java +1 -1
  23. package/android/src/main/java/com/{shopify/reactnative → reactnative}/skia/SkiaSurfaceView.java +13 -3
  24. package/android/src/main/java/com/{shopify/reactnative → reactnative}/skia/SkiaTextureView.java +5 -3
  25. package/android/src/main/java/com/{shopify/reactnative → reactnative}/skia/SkiaViewAPI.java +1 -1
  26. package/android/src/main/java/com/{shopify/reactnative → reactnative}/skia/ViewScreenshotService.java +1 -1
  27. package/apple/MetalContext.mm +1 -1
  28. package/apple/RNSkiaModule.h +1 -10
  29. package/apple/RNSkiaModule.mm +2 -10
  30. package/apple/SkiaManager.h +0 -2
  31. package/apple/SkiaManager.mm +4 -6
  32. package/apple/SkiaPictureView.h +2 -2
  33. package/apple/SkiaPictureView.mm +0 -4
  34. package/apple/SkiaUIView.h +3 -18
  35. package/apple/SkiaUIView.mm +0 -30
  36. package/cpp/api/CustomBlendModes.h +17 -0
  37. package/cpp/api/JsiSkCanvas.h +19 -10
  38. package/cpp/jsi/ViewProperty.h +0 -4
  39. package/lib/commonjs/mock/index.js +0 -1
  40. package/lib/commonjs/mock/index.js.map +1 -1
  41. package/lib/commonjs/renderer/Canvas.d.ts +11 -3
  42. package/lib/commonjs/renderer/Canvas.js +8 -6
  43. package/lib/commonjs/renderer/Canvas.js.map +1 -1
  44. package/lib/commonjs/skia/web/JsiSkCanvas.js +9 -4
  45. package/lib/commonjs/skia/web/JsiSkCanvas.js.map +1 -1
  46. package/lib/commonjs/specs/SkiaPictureViewNativeComponent.d.ts +2 -0
  47. package/lib/commonjs/specs/SkiaPictureViewNativeComponent.js.map +1 -1
  48. package/lib/commonjs/specs/SkiaPictureViewNativeComponent.web.d.ts +3 -1
  49. package/lib/commonjs/specs/SkiaPictureViewNativeComponent.web.js +3 -0
  50. package/lib/commonjs/specs/SkiaPictureViewNativeComponent.web.js.map +1 -1
  51. package/lib/commonjs/views/SkiaPictureView.js +2 -12
  52. package/lib/commonjs/views/SkiaPictureView.js.map +1 -1
  53. package/lib/commonjs/views/types.d.ts +19 -8
  54. package/lib/commonjs/views/types.js.map +1 -1
  55. package/lib/module/mock/index.js +0 -1
  56. package/lib/module/mock/index.js.map +1 -1
  57. package/lib/module/renderer/Canvas.d.ts +11 -3
  58. package/lib/module/renderer/Canvas.js +7 -5
  59. package/lib/module/renderer/Canvas.js.map +1 -1
  60. package/lib/module/skia/web/JsiSkCanvas.js +9 -4
  61. package/lib/module/skia/web/JsiSkCanvas.js.map +1 -1
  62. package/lib/module/specs/SkiaPictureViewNativeComponent.d.ts +2 -0
  63. package/lib/module/specs/SkiaPictureViewNativeComponent.js.map +1 -1
  64. package/lib/module/specs/SkiaPictureViewNativeComponent.web.d.ts +3 -1
  65. package/lib/module/specs/SkiaPictureViewNativeComponent.web.js +3 -0
  66. package/lib/module/specs/SkiaPictureViewNativeComponent.web.js.map +1 -1
  67. package/lib/module/views/SkiaPictureView.js +2 -12
  68. package/lib/module/views/SkiaPictureView.js.map +1 -1
  69. package/lib/module/views/types.d.ts +19 -8
  70. package/lib/module/views/types.js.map +1 -1
  71. package/lib/typescript/lib/commonjs/mock/index.d.ts +0 -1
  72. package/lib/typescript/lib/commonjs/renderer/Canvas.d.ts +2 -2
  73. package/lib/typescript/lib/commonjs/specs/SkiaPictureViewNativeComponent.web.d.ts +3 -1
  74. package/lib/typescript/lib/module/mock/index.d.ts +0 -1
  75. package/lib/typescript/lib/module/renderer/Canvas.d.ts +2 -2
  76. package/lib/typescript/lib/module/specs/SkiaPictureViewNativeComponent.web.d.ts +3 -1
  77. package/lib/typescript/src/renderer/Canvas.d.ts +11 -3
  78. package/lib/typescript/src/specs/SkiaPictureViewNativeComponent.d.ts +2 -0
  79. package/lib/typescript/src/specs/SkiaPictureViewNativeComponent.web.d.ts +3 -1
  80. package/lib/typescript/src/views/types.d.ts +19 -8
  81. package/package.json +3 -3
  82. package/react-native-skia.podspec +4 -10
  83. package/src/mock/index.ts +0 -1
  84. package/src/renderer/Canvas.tsx +23 -5
  85. package/src/skia/web/JsiSkCanvas.ts +14 -9
  86. package/src/specs/SkiaPictureViewNativeComponent.ts +5 -0
  87. package/src/specs/SkiaPictureViewNativeComponent.web.ts +5 -0
  88. package/src/views/SkiaPictureView.tsx +2 -10
  89. package/src/views/types.ts +23 -10
  90. package/android/src/latest/java/com/shopify/reactnative/skia/ReactNativeCompatible.java +0 -11
  91. package/android/src/main/java/com/shopify/reactnative/skia/RNSkiaPackage.java +0 -79
  92. package/android/src/main/java/com/shopify/reactnative/skia/SkiaAHBView.java +0 -113
  93. package/android/src/main/java/com/shopify/reactnative/skia/SkiaBaseView.java +0 -136
  94. package/android/src/paper/java/com/facebook/react/viewmanagers/SkiaPictureViewManagerDelegate.java +0 -41
  95. package/android/src/paper/java/com/facebook/react/viewmanagers/SkiaPictureViewManagerInterface.java +0 -20
  96. package/android/src/paper/java/com/facebook/react/viewmanagers/SkiaWebGPUViewManagerDelegate.java +0 -35
  97. package/android/src/paper/java/com/facebook/react/viewmanagers/SkiaWebGPUViewManagerInterface.java +0 -17
  98. package/android/src/paper/java/com/shopify/reactnative/skia/NativeSkiaModuleSpec.java +0 -38
  99. package/android/src/reactnative74/java/com/shopify/reactnative/skia/ReactNativeCompatible.java +0 -14
  100. package/apple/SkiaPictureViewManager.h +0 -8
  101. package/apple/SkiaPictureViewManager.mm +0 -60
  102. package/apple/SkiaWebGPUView.h +0 -20
  103. package/apple/WebGPUMetalView.h +0 -12
@@ -21,24 +21,28 @@ class JniSkiaBaseView {
21
21
  public:
22
22
  JniSkiaBaseView(jni::alias_ref<JniSkiaManager::javaobject> skiaManager,
23
23
  std::shared_ptr<RNSkBaseAndroidView> skiaView)
24
- : _skiaAndroidView(std::move(skiaView)), _manager(skiaManager->cthis()) {}
24
+ : _skiaAndroidView(std::move(skiaView)),
25
+ _manager(skiaManager->cthis()->getSkiaManager()) {}
25
26
 
26
27
  ~JniSkiaBaseView() = default;
27
28
 
28
- std::shared_ptr<RNSkManager> getSkiaManager() {
29
- return _manager->getSkiaManager();
30
- }
29
+ // The manager is owned by the RNSkiaModule and is destroyed when the module
30
+ // is invalidated (reload). Fabric drops views on the UI thread while the
31
+ // module is invalidated on a background thread, so a view can outlive its
32
+ // manager: holding a weak reference makes a late unregister a no-op and a
33
+ // concurrent one keep the manager alive for the duration of the call.
34
+ std::shared_ptr<RNSkManager> getSkiaManager() { return _manager.lock(); }
31
35
 
32
36
  protected:
33
37
  virtual void surfaceAvailable(jobject surface, int width, int height,
34
- bool opaque, bool highBitDepth) {
35
- _skiaAndroidView->surfaceAvailable(surface, width, height, opaque,
38
+ bool isSurface, bool highBitDepth) {
39
+ _skiaAndroidView->surfaceAvailable(surface, width, height, isSurface,
36
40
  highBitDepth);
37
41
  }
38
42
 
39
43
  virtual void surfaceSizeChanged(jobject surface, int width, int height,
40
- bool opaque, bool highBitDepth) {
41
- _skiaAndroidView->surfaceSizeChanged(surface, width, height, opaque,
44
+ bool isSurface, bool highBitDepth) {
45
+ _skiaAndroidView->surfaceSizeChanged(surface, width, height, isSurface,
42
46
  highBitDepth);
43
47
  }
44
48
 
@@ -49,8 +53,11 @@ protected:
49
53
  }
50
54
 
51
55
  virtual void registerView(int nativeId) {
52
- getSkiaManager()->registerSkiaView(nativeId,
53
- _skiaAndroidView->getSkiaView());
56
+ auto manager = getSkiaManager();
57
+ if (manager == nullptr) {
58
+ return;
59
+ }
60
+ manager->registerSkiaView(nativeId, _skiaAndroidView->getSkiaView());
54
61
  }
55
62
 
56
63
  virtual void unregisterView() {
@@ -74,7 +81,7 @@ protected:
74
81
  std::shared_ptr<RNSkBaseAndroidView> _skiaAndroidView;
75
82
 
76
83
  private:
77
- JniSkiaManager *_manager;
84
+ std::weak_ptr<RNSkManager> _manager;
78
85
  };
79
86
 
80
87
  } // namespace RNSkia
@@ -5,7 +5,6 @@
5
5
  #include <fbjni/fbjni.h>
6
6
  #include <jsi/jsi.h>
7
7
  #include <memory>
8
- #include <react/jni/JRuntimeExecutor.h>
9
8
 
10
9
  #include "JniPlatformContext.h"
11
10
  #include "RNSkAndroidPlatformContext.h"
@@ -23,13 +22,13 @@ using JavaPlatformContext = jni::alias_ref<JniPlatformContext::javaobject>;
23
22
  class JniSkiaManager : public jni::HybridClass<JniSkiaManager> {
24
23
  public:
25
24
  static auto constexpr kJavaDescriptor =
26
- "Lcom/shopify/reactnative/skia/SkiaManager;";
25
+ "Lcom/reactnative/skia/SkiaManager;";
27
26
  static auto constexpr TAG = "ReactNativeSkia";
28
27
 
29
28
  static jni::local_ref<jni::HybridClass<JniSkiaManager>::jhybriddata>
30
29
  initHybrid(jni::alias_ref<jhybridobject> jThis, jlong jsContext,
31
- jni::alias_ref<facebook::react::JRuntimeExecutor::javaobject>
32
- jRuntimeExecutor,
30
+ jni::alias_ref<facebook::react::CallInvokerHolder::javaobject>
31
+ jsCallInvokerHolder,
33
32
  JavaPlatformContext platformContext);
34
33
 
35
34
  static void registerNatives();
@@ -39,7 +39,7 @@ class JniSkiaPictureView : public jni::HybridClass<JniSkiaPictureView>,
39
39
  public JniSkiaBaseView {
40
40
  public:
41
41
  static auto constexpr kJavaDescriptor =
42
- "Lcom/shopify/reactnative/skia/SkiaPictureView;";
42
+ "Lcom/reactnative/skia/SkiaPictureView;";
43
43
 
44
44
  static jni::local_ref<jhybriddata>
45
45
  initHybrid(jni::alias_ref<jhybridobject> jThis,
@@ -63,15 +63,15 @@ public:
63
63
  }
64
64
 
65
65
  protected:
66
- void surfaceAvailable(jobject surface, int width, int height, bool opaque,
66
+ void surfaceAvailable(jobject surface, int width, int height, bool isSurface,
67
67
  bool highBitDepth) override {
68
- JniSkiaBaseView::surfaceAvailable(surface, width, height, opaque,
68
+ JniSkiaBaseView::surfaceAvailable(surface, width, height, isSurface,
69
69
  highBitDepth);
70
70
  }
71
71
 
72
- void surfaceSizeChanged(jobject surface, int width, int height, bool opaque,
72
+ void surfaceSizeChanged(jobject surface, int width, int height, bool isSurface,
73
73
  bool highBitDepth) override {
74
- JniSkiaBaseView::surfaceSizeChanged(surface, width, height, opaque,
74
+ JniSkiaBaseView::surfaceSizeChanged(surface, width, height, isSurface,
75
75
  highBitDepth);
76
76
  }
77
77
 
@@ -12,12 +12,12 @@ namespace RNSkia {
12
12
  class RNSkBaseAndroidView {
13
13
  public:
14
14
  virtual void surfaceAvailable(jobject surface, int width, int height,
15
- bool opaque, bool highBitDepth) = 0;
15
+ bool isSurface, bool highBitDepth) = 0;
16
16
 
17
17
  virtual void surfaceDestroyed() = 0;
18
18
 
19
19
  virtual void surfaceSizeChanged(jobject surface, int width, int height,
20
- bool opaque, bool highBitDepth) = 0;
20
+ bool isSurface, bool highBitDepth) = 0;
21
21
 
22
22
  virtual float getPixelDensity() = 0;
23
23
 
@@ -34,10 +34,10 @@ public:
34
34
  std::make_shared<RNSkOpenGLCanvasProvider>(
35
35
  std::bind(&RNSkia::RNSkView::requestRedraw, this), context)) {}
36
36
 
37
- void surfaceAvailable(jobject surface, int width, int height, bool opaque,
37
+ void surfaceAvailable(jobject surface, int width, int height, bool isSurface,
38
38
  bool highBitDepth) override {
39
39
  std::static_pointer_cast<RNSkOpenGLCanvasProvider>(T::getCanvasProvider())
40
- ->surfaceAvailable(surface, width, height, opaque, highBitDepth);
40
+ ->surfaceAvailable(surface, width, height, isSurface, highBitDepth);
41
41
  RNSkView::redraw();
42
42
  }
43
43
 
@@ -46,10 +46,10 @@ public:
46
46
  ->surfaceDestroyed();
47
47
  }
48
48
 
49
- void surfaceSizeChanged(jobject surface, int width, int height, bool opaque,
49
+ void surfaceSizeChanged(jobject surface, int width, int height, bool isSurface,
50
50
  bool highBitDepth) override {
51
51
  std::static_pointer_cast<RNSkOpenGLCanvasProvider>(T::getCanvasProvider())
52
- ->surfaceSizeChanged(surface, width, height, opaque, highBitDepth);
52
+ ->surfaceSizeChanged(surface, width, height, isSurface, highBitDepth);
53
53
  // This is only need for the first time to frame, this renderImmediate call
54
54
  // will invoke updateTexImage for the previous frame
55
55
  RNSkView::redraw();
@@ -78,7 +78,7 @@ bool RNSkOpenGLCanvasProvider::renderToCanvas(
78
78
 
79
79
  void RNSkOpenGLCanvasProvider::surfaceAvailable(jobject jSurfaceTexture,
80
80
  int width, int height,
81
- bool opaque,
81
+ bool isSurface,
82
82
  bool highBitDepth) {
83
83
  // Release the old surface
84
84
  _surfaceHolder = nullptr;
@@ -86,7 +86,7 @@ void RNSkOpenGLCanvasProvider::surfaceAvailable(jobject jSurfaceTexture,
86
86
  // Create renderer!
87
87
  ANativeWindow *window = nullptr;
88
88
  JNIEnv *env = facebook::jni::Environment::current();
89
- if (!opaque) {
89
+ if (!isSurface) {
90
90
  _jSurfaceTexture = env->NewGlobalRef(jSurfaceTexture);
91
91
  jclass surfaceClass = env->FindClass("android/view/Surface");
92
92
  jmethodID surfaceConstructor = env->GetMethodID(
@@ -131,7 +131,7 @@ void RNSkOpenGLCanvasProvider::surfaceDestroyed() {
131
131
  }
132
132
 
133
133
  void RNSkOpenGLCanvasProvider::surfaceSizeChanged(jobject jSurface, int width,
134
- int height, bool opaque,
134
+ int height, bool isSurface,
135
135
  bool highBitDepth) {
136
136
  if (width == 0 && height == 0) {
137
137
  // Setting width/height to zero is nothing we need to care about when
@@ -141,7 +141,7 @@ void RNSkOpenGLCanvasProvider::surfaceSizeChanged(jobject jSurface, int width,
141
141
 
142
142
  if (_surfaceHolder == nullptr) {
143
143
  _surfaceHolder = nullptr;
144
- surfaceAvailable(jSurface, width, height, opaque, highBitDepth);
144
+ surfaceAvailable(jSurface, width, height, isSurface, highBitDepth);
145
145
  } else {
146
146
  _surfaceHolder->resize(width, height);
147
147
  }
@@ -27,12 +27,12 @@ public:
27
27
 
28
28
  bool renderToCanvas(const std::function<void(SkCanvas *)> &cb) override;
29
29
 
30
- void surfaceAvailable(jobject surface, int width, int height, bool opaque,
30
+ void surfaceAvailable(jobject surface, int width, int height, bool isSurface,
31
31
  bool highBitDepth);
32
32
 
33
33
  void surfaceDestroyed();
34
34
 
35
- void surfaceSizeChanged(jobject jSurface, int width, int height, bool opaque,
35
+ void surfaceSizeChanged(jobject jSurface, int width, int height, bool isSurface,
36
36
  bool highBitDepth);
37
37
 
38
38
  private:
@@ -1,6 +1,6 @@
1
1
  <!-- AndroidManifest.xml -->
2
2
 
3
3
  <manifest xmlns:android="http://schemas.android.com/apk/res/android"
4
- package="com.shopify.reactnative.skia">
4
+ package="com.reactnative.skia">
5
5
 
6
6
  </manifest>
@@ -1,4 +1,4 @@
1
- package com.shopify.reactnative.skia;
1
+ package com.reactnative.skia;
2
2
 
3
3
  import android.os.Handler;
4
4
  import android.os.Looper;
@@ -1,4 +1,4 @@
1
- package com.shopify.reactnative.skia;
1
+ package com.reactnative.skia;
2
2
 
3
3
  import android.content.Context;
4
4
  import android.graphics.ImageFormat;
@@ -1,6 +1,6 @@
1
1
  // RnskiaModule.java
2
2
 
3
- package com.shopify.reactnative.skia;
3
+ package com.reactnative.skia;
4
4
 
5
5
  import android.util.Log;
6
6
 
@@ -17,11 +17,6 @@ public class RNSkiaModule extends NativeSkiaModuleSpec {
17
17
 
18
18
  private final WeakReference<ReactApplicationContext> weakReactContext;
19
19
  private SkiaManager skiaManager;
20
- private static volatile boolean sIsValid = false;
21
-
22
- public static boolean isModuleValid() {
23
- return sIsValid;
24
- }
25
20
 
26
21
  public RNSkiaModule(ReactApplicationContext reactContext) {
27
22
  super(reactContext);
@@ -31,7 +26,6 @@ public class RNSkiaModule extends NativeSkiaModuleSpec {
31
26
  @Override
32
27
  public void invalidate() {
33
28
  super.invalidate();
34
- sIsValid = false;
35
29
 
36
30
  if (this.skiaManager != null) {
37
31
  this.skiaManager.invalidate();
@@ -64,7 +58,6 @@ public class RNSkiaModule extends NativeSkiaModuleSpec {
64
58
  return false;
65
59
  }
66
60
  skiaManager = new SkiaManager(context);
67
- sIsValid = true;
68
61
  return true;
69
62
  } catch (Exception exception) {
70
63
  Log.e(NAME, "Failed to initialize Skia Manager!", exception);
@@ -0,0 +1,57 @@
1
+ // RnskiaPackage.java
2
+
3
+ package com.reactnative.skia;
4
+
5
+ import androidx.annotation.Nullable;
6
+
7
+ import java.util.Arrays;
8
+ import java.util.HashMap;
9
+ import java.util.List;
10
+ import java.util.Map;
11
+
12
+ import com.facebook.react.BaseReactPackage;
13
+ import com.facebook.react.ReactPackage;
14
+ import com.facebook.react.bridge.NativeModule;
15
+ import com.facebook.react.bridge.ReactApplicationContext;
16
+ import com.facebook.react.module.model.ReactModuleInfo;
17
+ import com.facebook.react.module.model.ReactModuleInfoProvider;
18
+ import com.facebook.react.uimanager.ViewManager;
19
+
20
+ // `implements ReactPackage` is redundant (BaseReactPackage already implements it)
21
+ // but required: older @react-native-community/cli versions only autolink
22
+ // classes matching `implements ReactPackage` or `extends TurboReactPackage`.
23
+ public class RNSkiaPackage extends BaseReactPackage implements ReactPackage {
24
+ @Nullable
25
+ @Override
26
+ public NativeModule getModule(String name, ReactApplicationContext reactApplicationContext) {
27
+ if (RNSkiaModule.NAME.equals(name)) {
28
+ return new RNSkiaModule(reactApplicationContext);
29
+ }
30
+ return null;
31
+ }
32
+
33
+ @Override
34
+ public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
35
+ return Arrays.<ViewManager>asList(
36
+ new SkiaPictureViewManager()
37
+ );
38
+ }
39
+
40
+ @Override
41
+ public ReactModuleInfoProvider getReactModuleInfoProvider() {
42
+ return () -> {
43
+ final Map<String, ReactModuleInfo> reactModuleInfoMap = new HashMap<>();
44
+ reactModuleInfoMap.put(
45
+ RNSkiaModule.NAME,
46
+ new ReactModuleInfo(
47
+ RNSkiaModule.NAME,
48
+ RNSkiaModule.class.getName(),
49
+ false, // canOverrideExistingModule
50
+ false, // needsEagerInit
51
+ false, // isCxxModule
52
+ true // isTurboModule
53
+ ));
54
+ return reactModuleInfoMap;
55
+ };
56
+ }
57
+ }
@@ -0,0 +1,185 @@
1
+ package com.reactnative.skia;
2
+
3
+ import android.content.Context;
4
+ import android.graphics.SurfaceTexture;
5
+ import android.util.Log;
6
+ import android.view.MotionEvent;
7
+ import android.view.Surface;
8
+ import android.view.View;
9
+
10
+ import com.facebook.react.uimanager.PointerEvents;
11
+ import com.facebook.react.views.view.ReactViewGroup;
12
+
13
+ public abstract class SkiaBaseView extends ReactViewGroup implements SkiaViewAPI {
14
+ // Backing view kinds, see updateView().
15
+ private static final int KIND_SURFACE_VIEW = 0;
16
+ private static final int KIND_TEXTURE_VIEW = 1;
17
+
18
+ private View mView;
19
+
20
+ // Props, applied together in updateView().
21
+ private boolean mOpaque = false;
22
+ private String mSurfaceType = "auto";
23
+ private boolean mZOrderOnTop = false;
24
+ private boolean mHighBitDepth = false;
25
+
26
+ // What the current backing view was created with.
27
+ private int mAppliedKind = -1;
28
+ private boolean mAppliedZOrderOnTop;
29
+ private boolean mAppliedHighBitDepth;
30
+
31
+ private final boolean debug = false;
32
+ private final String tag = "SkiaView";
33
+
34
+ public SkiaBaseView(Context context) {
35
+ super(context);
36
+ }
37
+
38
+ @Override
39
+ public boolean dispatchTouchEvent(MotionEvent ev) {
40
+ // When pointerEvents is "none" or "box-none", make this view completely
41
+ // transparent to touch dispatch so events pass through to views behind it
42
+ if (!PointerEvents.canBeTouchTarget(getPointerEvents())) {
43
+ return false;
44
+ }
45
+ return super.dispatchTouchEvent(ev);
46
+ }
47
+
48
+ public void setOpaque(boolean value) {
49
+ mOpaque = value;
50
+ }
51
+
52
+ public void setSurfaceType(String value) {
53
+ mSurfaceType = value == null ? "auto" : value;
54
+ }
55
+
56
+ public void setZOrderOnTop(boolean value) {
57
+ mZOrderOnTop = value;
58
+ }
59
+
60
+ public void setHighBitDepth(boolean value) {
61
+ mHighBitDepth = value;
62
+ }
63
+
64
+ // Resolve the backing view from the props. "auto" picks SurfaceView for an
65
+ // opaque canvas and TextureView for a non-opaque one.
66
+ private int resolveKind() {
67
+ if ("SurfaceView".equals(mSurfaceType)) {
68
+ return KIND_SURFACE_VIEW;
69
+ }
70
+ if ("TextureView".equals(mSurfaceType)) {
71
+ return KIND_TEXTURE_VIEW;
72
+ }
73
+ return mOpaque ? KIND_SURFACE_VIEW : KIND_TEXTURE_VIEW;
74
+ }
75
+
76
+ // The 10-bit buffer format only has 2 bits of alpha, which would visibly
77
+ // break translucency, and the extra precision would be lost in the 8-bit
78
+ // composition pass of a TextureView anyway. So the flag only applies to an
79
+ // opaque SurfaceView.
80
+ private boolean resolveHighBitDepth(int kind) {
81
+ if (!mHighBitDepth) {
82
+ return false;
83
+ }
84
+ if (kind != KIND_SURFACE_VIEW || !mOpaque) {
85
+ Log.w(tag, "highBitDepth requires an opaque SurfaceView on Android, falling back to the 8-bit format");
86
+ return false;
87
+ }
88
+ return true;
89
+ }
90
+
91
+ // Apply the complete prop transaction once, after every prop has arrived.
92
+ // Only a change of backing view, or of a setting the view must know before
93
+ // it attaches (zOrderOnTop, the buffer format), replaces the child; opacity
94
+ // is applied in place.
95
+ void updateView() {
96
+ int kind = resolveKind();
97
+ boolean zOrderOnTop = kind == KIND_SURFACE_VIEW && mZOrderOnTop;
98
+ boolean highBitDepth = resolveHighBitDepth(kind);
99
+ if (mView == null
100
+ || kind != mAppliedKind
101
+ || zOrderOnTop != mAppliedZOrderOnTop
102
+ || highBitDepth != mAppliedHighBitDepth) {
103
+ if (mView != null) {
104
+ removeView(mView);
105
+ }
106
+ mAppliedKind = kind;
107
+ mAppliedZOrderOnTop = zOrderOnTop;
108
+ mAppliedHighBitDepth = highBitDepth;
109
+ mView = kind == KIND_SURFACE_VIEW
110
+ ? new SkiaSurfaceView(getContext(), this, debug, zOrderOnTop, mOpaque)
111
+ : new SkiaTextureView(getContext(), this, debug, mOpaque);
112
+ addView(mView);
113
+ // React Native sizes native children explicitly through onLayout, so
114
+ // the requestLayout triggered by addView is ignored; size the new
115
+ // child ourselves or it stays 0x0 and never gets a surface.
116
+ if (getWidth() > 0 || getHeight() > 0) {
117
+ mView.layout(0, 0, getWidth(), getHeight());
118
+ }
119
+ } else if (kind == KIND_SURFACE_VIEW) {
120
+ ((SkiaSurfaceView) mView).setOpaque(mOpaque);
121
+ } else {
122
+ ((SkiaTextureView) mView).setOpaque(mOpaque);
123
+ }
124
+ }
125
+
126
+ void dropInstance() {
127
+ unregisterView();
128
+ }
129
+
130
+ @Override
131
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
132
+ super.onLayout(changed, left, top, right, bottom);
133
+ if (mView != null) {
134
+ mView.layout(0, 0, right - left, bottom - top);
135
+ }
136
+ }
137
+
138
+ // SurfaceView callbacks: the native side receives an android.view.Surface.
139
+
140
+ @Override
141
+ public void onSurfaceCreated(Surface surface, int width, int height) {
142
+ surfaceAvailable(surface, width, height, true, mAppliedHighBitDepth);
143
+ }
144
+
145
+ @Override
146
+ public void onSurfaceChanged(Surface surface, int width, int height) {
147
+ Log.i(tag, "onSurfaceChanged " + width + "/" + height);
148
+ surfaceSizeChanged(surface, width, height, true, mAppliedHighBitDepth);
149
+ }
150
+
151
+ // TextureView callbacks: the native side receives a SurfaceTexture and
152
+ // drives updateTexImage itself. The 10-bit format is never used here.
153
+
154
+ @Override
155
+ public void onSurfaceTextureCreated(SurfaceTexture surface, int width, int height) {
156
+ surfaceAvailable(surface, width, height, false, false);
157
+ }
158
+
159
+ @Override
160
+ public void onSurfaceTextureChanged(SurfaceTexture surface, int width, int height) {
161
+ Log.i(tag, "onSurfaceTextureSizeChanged " + width + "/" + height);
162
+ surfaceSizeChanged(surface, width, height, false, false);
163
+ }
164
+
165
+ @Override
166
+ public void onSurfaceDestroyed() {
167
+ surfaceDestroyed();
168
+ }
169
+
170
+ // isSurface tells the native side whether `surface` is an
171
+ // android.view.Surface (SurfaceView) or a SurfaceTexture (TextureView).
172
+ protected abstract void surfaceAvailable(Object surface, int width, int height, boolean isSurface, boolean highBitDepth);
173
+
174
+ protected abstract void surfaceSizeChanged(Object surface, int width, int height, boolean isSurface, boolean highBitDepth);
175
+
176
+ protected abstract void surfaceDestroyed();
177
+
178
+ protected abstract void setDebugMode(boolean show);
179
+
180
+ protected abstract void registerView(int nativeId);
181
+
182
+ protected abstract void unregisterView();
183
+
184
+ protected abstract int[] getBitmap(int width, int height);
185
+ }
@@ -1,4 +1,4 @@
1
- package com.shopify.reactnative.skia;
1
+ package com.reactnative.skia;
2
2
 
3
3
  import com.facebook.react.uimanager.PointerEvents;
4
4
  import com.facebook.react.uimanager.ViewProps;
@@ -33,6 +33,25 @@ public abstract class SkiaBaseViewManager<T extends SkiaBaseView> extends ReactV
33
33
  ((SkiaBaseView)view).setHighBitDepth(value);
34
34
  }
35
35
 
36
+ @ReactProp(name = "androidSurfaceType")
37
+ public void setAndroidSurfaceType(T view, @Nullable String value) {
38
+ ((SkiaBaseView)view).setSurfaceType(value);
39
+ }
40
+
41
+ @ReactProp(name = "androidZOrderOnTop")
42
+ public void setAndroidZOrderOnTop(T view, boolean value) {
43
+ ((SkiaBaseView)view).setZOrderOnTop(value);
44
+ }
45
+
46
+ // The backing view depends on several props (opaque, androidSurfaceType,
47
+ // androidZOrderOnTop, highBitDepth), so it is resolved once per transaction
48
+ // rather than in each setter.
49
+ @Override
50
+ protected void onAfterUpdateTransaction(@NonNull ReactViewGroup view) {
51
+ super.onAfterUpdateTransaction(view);
52
+ ((SkiaBaseView)view).updateView();
53
+ }
54
+
36
55
  @ReactProp(name = ViewProps.POINTER_EVENTS)
37
56
  public void setPointerEvents(T view, @Nullable String pointerEventsStr) {
38
57
  view.setPointerEvents(PointerEvents.parsePointerEvents(pointerEventsStr));
@@ -1,9 +1,10 @@
1
- package com.shopify.reactnative.skia;
1
+ package com.reactnative.skia;
2
2
 
3
3
  import com.facebook.jni.HybridData;
4
4
  import com.facebook.proguard.annotations.DoNotStrip;
5
5
  import com.facebook.react.bridge.ReactContext;
6
- import com.facebook.react.bridge.RuntimeExecutor;
6
+ import com.facebook.react.turbomodule.core.CallInvokerHolderImpl;
7
+ import com.facebook.react.turbomodule.core.interfaces.CallInvokerHolder;
7
8
 
8
9
  @DoNotStrip
9
10
  public class SkiaManager {
@@ -22,11 +23,15 @@ public class SkiaManager {
22
23
  super();
23
24
  mContext = context;
24
25
 
25
- RuntimeExecutor runtimeExecutor = ReactNativeCompatible.getRuntimeExecutor(context);
26
+ CallInvokerHolder jsCallInvokerHolder = context.getJSCallInvokerHolder();
27
+ if (jsCallInvokerHolder == null) {
28
+ throw new IllegalStateException("React instance is not ready: no JS CallInvoker available");
29
+ }
26
30
 
27
31
  mPlatformContext = new PlatformContext(context);
28
32
 
29
- mHybridData = initHybrid(context.getJavaScriptContextHolder().get(), runtimeExecutor, mPlatformContext);
33
+ mHybridData = initHybrid(context.getJavaScriptContextHolder().get(),
34
+ (CallInvokerHolderImpl) jsCallInvokerHolder, mPlatformContext);
30
35
 
31
36
  initializeRuntime();
32
37
  }
@@ -44,10 +49,10 @@ public class SkiaManager {
44
49
  }
45
50
 
46
51
  // private C++ functions
47
- private native HybridData initHybrid(long jsContext, RuntimeExecutor runtimeExecutor,
52
+ private native HybridData initHybrid(long jsContext, CallInvokerHolderImpl jsCallInvokerHolder,
48
53
  PlatformContext platformContext);
49
54
 
50
55
  private native void initializeRuntime();
51
56
  public native void invalidate();
52
57
 
53
- }
58
+ }
@@ -1,4 +1,4 @@
1
- package com.shopify.reactnative.skia;
1
+ package com.reactnative.skia;
2
2
 
3
3
  import android.content.Context;
4
4
  import android.graphics.Bitmap;
@@ -67,9 +67,9 @@ public class SkiaPictureView extends SkiaBaseView {
67
67
 
68
68
  private native HybridData initHybrid(SkiaManager skiaManager);
69
69
 
70
- protected native void surfaceAvailable(Object surface, int width, int height, boolean opaque, boolean highBitDepth);
70
+ protected native void surfaceAvailable(Object surface, int width, int height, boolean isSurface, boolean highBitDepth);
71
71
 
72
- protected native void surfaceSizeChanged(Object surface, int width, int height, boolean opaque, boolean highBitDepth);
72
+ protected native void surfaceSizeChanged(Object surface, int width, int height, boolean isSurface, boolean highBitDepth);
73
73
 
74
74
  protected native void surfaceDestroyed();
75
75
 
@@ -1,4 +1,4 @@
1
- package com.shopify.reactnative.skia;
1
+ package com.reactnative.skia;
2
2
 
3
3
  import com.facebook.react.uimanager.ThemedReactContext;
4
4
  import com.facebook.react.viewmanagers.SkiaPictureViewManagerDelegate;
@@ -1,7 +1,8 @@
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;
5
+ import android.graphics.PixelFormat;
5
6
  import android.view.SurfaceHolder;
6
7
  import android.view.SurfaceView;
7
8
  import androidx.annotation.NonNull;
@@ -12,13 +13,22 @@ public class SkiaSurfaceView extends SurfaceView implements SurfaceHolder.Callba
12
13
  SkiaViewAPI mApi;
13
14
  boolean mDebug;
14
15
 
15
- public SkiaSurfaceView(Context context, SkiaViewAPI api, boolean debug) {
16
+ public SkiaSurfaceView(Context context, SkiaViewAPI api, boolean debug, boolean zOrderOnTop, boolean opaque) {
16
17
  super(context);
17
18
  mApi = api;
18
19
  mDebug = debug;
20
+ // Must be set before the surface is created.
21
+ setZOrderOnTop(zOrderOnTop);
22
+ setOpaque(opaque);
19
23
  getHolder().addCallback(this);
20
24
  }
21
25
 
26
+ // The format drives the compositor's opaque flag for this layer. It can
27
+ // change on a live surface: SurfaceView reports it through surfaceChanged.
28
+ public void setOpaque(boolean opaque) {
29
+ getHolder().setFormat(opaque ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT);
30
+ }
31
+
22
32
  @Override
23
33
  protected void onDetachedFromWindow() {
24
34
  super.onDetachedFromWindow();
@@ -39,4 +49,4 @@ public class SkiaSurfaceView extends SurfaceView implements SurfaceHolder.Callba
39
49
  public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
40
50
  mApi.onSurfaceDestroyed();
41
51
  }
42
- }
52
+ }