react-native-worklets 0.0.1-alpha → 0.1.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 (246) hide show
  1. package/Common/cpp/worklets/AnimationFrameQueue/AnimationFrameBatchinator.cpp +71 -0
  2. package/Common/cpp/worklets/AnimationFrameQueue/AnimationFrameBatchinator.h +38 -0
  3. package/Common/cpp/worklets/NativeModules/WorkletsModuleProxy.cpp +131 -0
  4. package/Common/cpp/worklets/NativeModules/WorkletsModuleProxy.h +82 -0
  5. package/Common/cpp/worklets/NativeModules/WorkletsModuleProxySpec.cpp +72 -0
  6. package/Common/cpp/worklets/NativeModules/WorkletsModuleProxySpec.h +44 -0
  7. package/Common/cpp/worklets/Registries/EventHandlerRegistry.cpp +94 -0
  8. package/Common/cpp/worklets/Registries/EventHandlerRegistry.h +49 -0
  9. package/Common/cpp/worklets/Registries/WorkletRuntimeRegistry.cpp +8 -0
  10. package/Common/cpp/worklets/Registries/WorkletRuntimeRegistry.h +39 -0
  11. package/Common/cpp/worklets/SharedItems/Shareables.cpp +326 -0
  12. package/Common/cpp/worklets/SharedItems/Shareables.h +345 -0
  13. package/Common/cpp/worklets/Tools/AsyncQueue.cpp +52 -0
  14. package/Common/cpp/worklets/Tools/AsyncQueue.h +35 -0
  15. package/Common/cpp/worklets/Tools/Defs.h +10 -0
  16. package/Common/cpp/worklets/Tools/JSISerializer.cpp +342 -0
  17. package/Common/cpp/worklets/Tools/JSISerializer.h +47 -0
  18. package/Common/cpp/worklets/Tools/JSLogger.cpp +16 -0
  19. package/Common/cpp/worklets/Tools/JSLogger.h +20 -0
  20. package/Common/cpp/worklets/Tools/JSScheduler.cpp +10 -0
  21. package/Common/cpp/worklets/Tools/JSScheduler.h +29 -0
  22. package/Common/cpp/worklets/Tools/PlatformLogger.h +16 -0
  23. package/Common/cpp/worklets/Tools/SingleInstanceChecker.h +72 -0
  24. package/Common/cpp/worklets/Tools/ThreadSafeQueue.h +49 -0
  25. package/Common/cpp/worklets/Tools/UIScheduler.cpp +19 -0
  26. package/Common/cpp/worklets/Tools/UIScheduler.h +22 -0
  27. package/Common/cpp/worklets/Tools/WorkletEventHandler.cpp +29 -0
  28. package/Common/cpp/worklets/Tools/WorkletEventHandler.h +41 -0
  29. package/Common/cpp/worklets/Tools/WorkletsJSIUtils.cpp +26 -0
  30. package/Common/cpp/worklets/Tools/WorkletsJSIUtils.h +199 -0
  31. package/Common/cpp/worklets/WorkletRuntime/RNRuntimeWorkletDecorator.cpp +20 -0
  32. package/Common/cpp/worklets/WorkletRuntime/RNRuntimeWorkletDecorator.h +19 -0
  33. package/Common/cpp/worklets/WorkletRuntime/RuntimeInitialization.md +191 -0
  34. package/Common/cpp/worklets/WorkletRuntime/UIRuntimeDecorator.cpp +19 -0
  35. package/Common/cpp/worklets/WorkletRuntime/UIRuntimeDecorator.h +16 -0
  36. package/Common/cpp/worklets/WorkletRuntime/WorkletHermesRuntime.cpp +108 -0
  37. package/Common/cpp/worklets/WorkletRuntime/WorkletHermesRuntime.h +127 -0
  38. package/Common/cpp/worklets/WorkletRuntime/WorkletRuntime.cpp +183 -0
  39. package/Common/cpp/worklets/WorkletRuntime/WorkletRuntime.h +90 -0
  40. package/Common/cpp/worklets/WorkletRuntime/WorkletRuntimeCollector.h +36 -0
  41. package/Common/cpp/worklets/WorkletRuntime/WorkletRuntimeDecorator.cpp +179 -0
  42. package/Common/cpp/worklets/WorkletRuntime/WorkletRuntimeDecorator.h +22 -0
  43. package/LICENSE +20 -0
  44. package/README.md +27 -0
  45. package/RNWorklets.podspec +70 -0
  46. package/android/CMakeLists.txt +56 -0
  47. package/android/build.gradle +313 -0
  48. package/android/gradle.properties +5 -0
  49. package/android/proguard-rules.pro +3 -0
  50. package/android/spotless.gradle +9 -0
  51. package/android/src/main/AndroidManifest.xml +2 -0
  52. package/android/src/main/cpp/worklets/CMakeLists.txt +85 -0
  53. package/android/src/main/cpp/worklets/android/AndroidUIScheduler.cpp +63 -0
  54. package/android/src/main/cpp/worklets/android/AndroidUIScheduler.h +41 -0
  55. package/android/src/main/cpp/worklets/android/AnimationFrameCallback.h +32 -0
  56. package/android/src/main/cpp/worklets/android/PlatformLogger.cpp +29 -0
  57. package/android/src/main/cpp/worklets/android/WorkletsModule.cpp +83 -0
  58. package/android/src/main/cpp/worklets/android/WorkletsModule.h +63 -0
  59. package/android/src/main/cpp/worklets/android/WorkletsOnLoad.cpp +13 -0
  60. package/android/src/main/java/com/swmansion/worklets/AndroidUIScheduler.java +60 -0
  61. package/android/src/main/java/com/swmansion/worklets/AnimationFrameQueue/AnimationFrameCallback.java +20 -0
  62. package/android/src/main/java/com/swmansion/worklets/AnimationFrameQueue/AnimationFrameQueue.java +113 -0
  63. package/android/src/main/java/com/swmansion/worklets/JSCallInvokerResolver.java +27 -0
  64. package/android/src/main/java/com/swmansion/worklets/WorkletsMessageQueueThread.java +16 -0
  65. package/android/src/main/java/com/swmansion/worklets/WorkletsMessageQueueThreadBase.java +72 -0
  66. package/android/src/main/java/com/swmansion/worklets/WorkletsModule.java +106 -0
  67. package/android/src/main/java/com/swmansion/worklets/WorkletsPackage.java +49 -0
  68. package/android/src/paper/com/swmansion/worklets/NativeWorkletsModuleSpec.java +26 -0
  69. package/apple/worklets/apple/AnimationFrameQueue.h +15 -0
  70. package/apple/worklets/apple/AnimationFrameQueue.mm +81 -0
  71. package/apple/worklets/apple/AssertJavaScriptQueue.h +14 -0
  72. package/apple/worklets/apple/AssertTurboModuleManagerQueue.h +16 -0
  73. package/apple/worklets/apple/IOSUIScheduler.h +14 -0
  74. package/apple/worklets/apple/IOSUIScheduler.mm +24 -0
  75. package/apple/worklets/apple/PlatformLogger.mm +31 -0
  76. package/apple/worklets/apple/SlowAnimations.h +8 -0
  77. package/apple/worklets/apple/SlowAnimations.mm +47 -0
  78. package/apple/worklets/apple/WorkletsDisplayLink.h +21 -0
  79. package/apple/worklets/apple/WorkletsMessageThread.h +16 -0
  80. package/apple/worklets/apple/WorkletsMessageThread.mm +32 -0
  81. package/apple/worklets/apple/WorkletsModule.h +10 -0
  82. package/apple/worklets/apple/WorkletsModule.mm +85 -0
  83. package/lib/module/PlatformChecker.js +35 -0
  84. package/lib/module/PlatformChecker.js.map +1 -0
  85. package/lib/module/WorkletsError.js +13 -0
  86. package/lib/module/WorkletsError.js.map +1 -0
  87. package/lib/module/WorkletsModule/JSWorklets.js +36 -0
  88. package/lib/module/WorkletsModule/JSWorklets.js.map +1 -0
  89. package/lib/module/WorkletsModule/NativeWorklets.js +39 -0
  90. package/lib/module/WorkletsModule/NativeWorklets.js.map +1 -0
  91. package/lib/module/WorkletsModule/index.js +4 -0
  92. package/lib/module/WorkletsModule/index.js.map +1 -0
  93. package/lib/module/WorkletsModule/workletsModuleInstance.js +7 -0
  94. package/lib/module/WorkletsModule/workletsModuleInstance.js.map +1 -0
  95. package/lib/module/WorkletsModule/workletsModuleInstance.web.js +5 -0
  96. package/lib/module/WorkletsModule/workletsModuleInstance.web.js.map +1 -0
  97. package/lib/module/WorkletsModule/workletsModuleProxy.js +4 -0
  98. package/lib/module/WorkletsModule/workletsModuleProxy.js.map +1 -0
  99. package/lib/module/animationFrameQueue/mockedRequestAnimationFrame.js +10 -0
  100. package/lib/module/animationFrameQueue/mockedRequestAnimationFrame.js.map +1 -0
  101. package/lib/module/animationFrameQueue/requestAnimationFrame.js +36 -0
  102. package/lib/module/animationFrameQueue/requestAnimationFrame.js.map +1 -0
  103. package/lib/module/errors.js +78 -0
  104. package/lib/module/errors.js.map +1 -0
  105. package/lib/module/index.js +17 -0
  106. package/lib/module/index.js.map +1 -0
  107. package/lib/module/initializers.js +158 -0
  108. package/lib/module/initializers.js.map +1 -0
  109. package/lib/module/logger/LogBox.js +15 -0
  110. package/lib/module/logger/LogBox.js.map +1 -0
  111. package/lib/module/logger/index.js +5 -0
  112. package/lib/module/logger/index.js.map +1 -0
  113. package/lib/module/logger/logger.js +137 -0
  114. package/lib/module/logger/logger.js.map +1 -0
  115. package/lib/module/privateGlobals.d.js +8 -0
  116. package/lib/module/privateGlobals.d.js.map +1 -0
  117. package/lib/module/runtimes.js +63 -0
  118. package/lib/module/runtimes.js.map +1 -0
  119. package/lib/module/shareableMappingCache.js +39 -0
  120. package/lib/module/shareableMappingCache.js.map +1 -0
  121. package/lib/module/shareables.js +417 -0
  122. package/lib/module/shareables.js.map +1 -0
  123. package/lib/module/specs/NativeWorkletsModule.js +5 -0
  124. package/lib/module/specs/NativeWorkletsModule.js.map +1 -0
  125. package/lib/module/specs/index.js +5 -0
  126. package/lib/module/specs/index.js.map +1 -0
  127. package/lib/module/threads.js +204 -0
  128. package/lib/module/threads.js.map +1 -0
  129. package/lib/module/valueUnpacker.js +83 -0
  130. package/lib/module/valueUnpacker.js.map +1 -0
  131. package/lib/module/workletFunction.js +37 -0
  132. package/lib/module/workletFunction.js.map +1 -0
  133. package/lib/module/workletTypes.js +12 -0
  134. package/lib/module/workletTypes.js.map +1 -0
  135. package/lib/typescript/PlatformChecker.d.ts +7 -0
  136. package/lib/typescript/PlatformChecker.d.ts.map +1 -0
  137. package/lib/typescript/WorkletsError.d.ts +3 -0
  138. package/lib/typescript/WorkletsError.d.ts.map +1 -0
  139. package/lib/typescript/WorkletsModule/JSWorklets.d.ts +3 -0
  140. package/lib/typescript/WorkletsModule/JSWorklets.d.ts.map +1 -0
  141. package/lib/typescript/WorkletsModule/NativeWorklets.d.ts +5 -0
  142. package/lib/typescript/WorkletsModule/NativeWorklets.d.ts.map +1 -0
  143. package/lib/typescript/WorkletsModule/index.d.ts +3 -0
  144. package/lib/typescript/WorkletsModule/index.d.ts.map +1 -0
  145. package/lib/typescript/WorkletsModule/workletsModuleInstance.d.ts +2 -0
  146. package/lib/typescript/WorkletsModule/workletsModuleInstance.d.ts.map +1 -0
  147. package/lib/typescript/WorkletsModule/workletsModuleInstance.web.d.ts +2 -0
  148. package/lib/typescript/WorkletsModule/workletsModuleInstance.web.d.ts.map +1 -0
  149. package/lib/typescript/WorkletsModule/workletsModuleProxy.d.ts +12 -0
  150. package/lib/typescript/WorkletsModule/workletsModuleProxy.d.ts.map +1 -0
  151. package/lib/typescript/animationFrameQueue/mockedRequestAnimationFrame.d.ts +6 -0
  152. package/lib/typescript/animationFrameQueue/mockedRequestAnimationFrame.d.ts.map +1 -0
  153. package/lib/typescript/animationFrameQueue/requestAnimationFrame.d.ts +2 -0
  154. package/lib/typescript/animationFrameQueue/requestAnimationFrame.d.ts.map +1 -0
  155. package/lib/typescript/errors.d.ts +19 -0
  156. package/lib/typescript/errors.d.ts.map +1 -0
  157. package/lib/typescript/index.d.ts +13 -0
  158. package/lib/typescript/index.d.ts.map +1 -0
  159. package/lib/typescript/initializers.d.ts +6 -0
  160. package/lib/typescript/initializers.d.ts.map +1 -0
  161. package/lib/typescript/logger/LogBox.d.ts +32 -0
  162. package/lib/typescript/logger/LogBox.d.ts.map +1 -0
  163. package/lib/typescript/logger/index.d.ts +3 -0
  164. package/lib/typescript/logger/index.d.ts.map +1 -0
  165. package/lib/typescript/logger/logger.d.ts +52 -0
  166. package/lib/typescript/logger/logger.d.ts.map +1 -0
  167. package/lib/typescript/runtimes.d.ts +16 -0
  168. package/lib/typescript/runtimes.d.ts.map +1 -0
  169. package/lib/typescript/shareableMappingCache.d.ts +16 -0
  170. package/lib/typescript/shareableMappingCache.d.ts.map +1 -0
  171. package/lib/typescript/shareables.d.ts +15 -0
  172. package/lib/typescript/shareables.d.ts.map +1 -0
  173. package/lib/typescript/specs/NativeWorkletsModule.d.ts +7 -0
  174. package/lib/typescript/specs/NativeWorkletsModule.d.ts.map +1 -0
  175. package/lib/typescript/specs/index.d.ts +3 -0
  176. package/lib/typescript/specs/index.d.ts.map +1 -0
  177. package/lib/typescript/threads.d.ts +49 -0
  178. package/lib/typescript/threads.d.ts.map +1 -0
  179. package/lib/typescript/valueUnpacker.d.ts +2 -0
  180. package/lib/typescript/valueUnpacker.d.ts.map +1 -0
  181. package/lib/typescript/workletFunction.d.ts +27 -0
  182. package/lib/typescript/workletFunction.d.ts.map +1 -0
  183. package/lib/typescript/workletTypes.d.ts +49 -0
  184. package/lib/typescript/workletTypes.d.ts.map +1 -0
  185. package/package.json +106 -8
  186. package/plugin/index.js +3 -0
  187. package/scripts/worklets_utils.rb +53 -0
  188. package/src/PlatformChecker.ts +43 -0
  189. package/src/WorkletsError.ts +13 -0
  190. package/src/WorkletsModule/JSWorklets.ts +57 -0
  191. package/src/WorkletsModule/NativeWorklets.ts +68 -0
  192. package/src/WorkletsModule/index.ts +7 -0
  193. package/src/WorkletsModule/workletsModuleInstance.ts +9 -0
  194. package/src/WorkletsModule/workletsModuleInstance.web.ts +5 -0
  195. package/src/WorkletsModule/workletsModuleProxy.ts +30 -0
  196. package/src/animationFrameQueue/mockedRequestAnimationFrame.ts +11 -0
  197. package/src/animationFrameQueue/requestAnimationFrame.ts +41 -0
  198. package/src/errors.ts +103 -0
  199. package/src/index.ts +42 -0
  200. package/src/initializers.ts +175 -0
  201. package/src/logger/LogBox.ts +55 -0
  202. package/src/logger/index.ts +3 -0
  203. package/src/logger/logger.ts +155 -0
  204. package/src/privateGlobals.d.ts +41 -0
  205. package/src/runtimes.ts +92 -0
  206. package/src/shareableMappingCache.ts +44 -0
  207. package/src/shareables.ts +577 -0
  208. package/src/specs/NativeWorkletsModule.ts +9 -0
  209. package/src/specs/index.ts +5 -0
  210. package/src/threads.ts +275 -0
  211. package/src/valueUnpacker.ts +110 -0
  212. package/src/workletFunction.ts +47 -0
  213. package/src/workletTypes.ts +76 -0
  214. package/Animated.js +0 -13
  215. package/AnimatedEvent.js +0 -167
  216. package/AnimatedImplementation.js +0 -666
  217. package/CoreAnimated.js +0 -43
  218. package/Easing.js +0 -236
  219. package/NativeAnimatedHelper.js +0 -226
  220. package/SpringConfig.js +0 -79
  221. package/animations/Animation.js +0 -36
  222. package/animations/DecayAnimation.js +0 -70
  223. package/animations/SpringAnimation.js +0 -125
  224. package/animations/TimingAnimation.js +0 -70
  225. package/bezier.js +0 -128
  226. package/createAnimatedComponent.js +0 -188
  227. package/nodes/AnimatedBlock.js +0 -19
  228. package/nodes/AnimatedClock.js +0 -76
  229. package/nodes/AnimatedCond.js +0 -23
  230. package/nodes/AnimatedDetach.js +0 -15
  231. package/nodes/AnimatedInterpolation.js +0 -338
  232. package/nodes/AnimatedNode.js +0 -97
  233. package/nodes/AnimatedOnChange.js +0 -28
  234. package/nodes/AnimatedOp.js +0 -17
  235. package/nodes/AnimatedProps.js +0 -154
  236. package/nodes/AnimatedSet.js +0 -19
  237. package/nodes/AnimatedStartClock.js +0 -21
  238. package/nodes/AnimatedStopClock.js +0 -21
  239. package/nodes/AnimatedStyle.js +0 -89
  240. package/nodes/AnimatedTracking.js +0 -36
  241. package/nodes/AnimatedTransform.js +0 -93
  242. package/nodes/AnimatedValue.js +0 -271
  243. package/nodes/AnimatedWithInput.js +0 -21
  244. package/nodes/SpringNode.js +0 -106
  245. package/nodes/TimingStep.js +0 -44
  246. package/utils.js +0 -28
@@ -0,0 +1,72 @@
1
+ package com.swmansion.worklets;
2
+
3
+ import com.facebook.proguard.annotations.DoNotStrip;
4
+ import com.facebook.react.bridge.queue.MessageQueueThread;
5
+ import com.facebook.react.bridge.queue.MessageQueueThreadImpl;
6
+ import com.facebook.react.bridge.queue.MessageQueueThreadPerfStats;
7
+ import com.facebook.react.bridge.queue.MessageQueueThreadSpec;
8
+ import java.lang.reflect.Field;
9
+ import java.util.concurrent.Callable;
10
+ import java.util.concurrent.Future;
11
+
12
+ // This class is an almost exact copy of MessageQueueThreadImpl taken from here:
13
+ // https://github.com/facebook/react-native/blob/main/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadImpl.java
14
+ // The only method that has changed is `quitSynchronous()` (see comment above
15
+ // function implementation for details).
16
+ @DoNotStrip
17
+ public abstract class WorkletsMessageQueueThreadBase implements MessageQueueThread {
18
+ protected final MessageQueueThreadImpl messageQueueThread;
19
+
20
+ public WorkletsMessageQueueThreadBase() {
21
+ messageQueueThread =
22
+ MessageQueueThreadImpl.create(
23
+ MessageQueueThreadSpec.mainThreadSpec(),
24
+ exception -> {
25
+ throw new RuntimeException(exception);
26
+ });
27
+ }
28
+
29
+ @Override
30
+ public <T> Future<T> callOnQueue(Callable<T> callable) {
31
+ return messageQueueThread.callOnQueue(callable);
32
+ }
33
+
34
+ @Override
35
+ public boolean isOnThread() {
36
+ return messageQueueThread.isOnThread();
37
+ }
38
+
39
+ @Override
40
+ public void assertIsOnThread() {
41
+ messageQueueThread.assertIsOnThread();
42
+ }
43
+
44
+ @Override
45
+ public void assertIsOnThread(String s) {
46
+ messageQueueThread.assertIsOnThread(s);
47
+ }
48
+
49
+ // We don't want to quit the main looper (which is what MessageQueueThreadImpl would have done),
50
+ // but we still want to prevent anything else from executing.
51
+ @Override
52
+ public void quitSynchronous() {
53
+ try {
54
+ Field mIsFinished = messageQueueThread.getClass().getDeclaredField("mIsFinished");
55
+ mIsFinished.setAccessible(true);
56
+ mIsFinished.set(messageQueueThread, true);
57
+ mIsFinished.setAccessible(false);
58
+ } catch (NoSuchFieldException | IllegalAccessException e) {
59
+ e.printStackTrace();
60
+ }
61
+ }
62
+
63
+ @Override
64
+ public MessageQueueThreadPerfStats getPerfStats() {
65
+ return messageQueueThread.getPerfStats();
66
+ }
67
+
68
+ @Override
69
+ public void resetPerfStats() {
70
+ messageQueueThread.resetPerfStats();
71
+ }
72
+ }
@@ -0,0 +1,106 @@
1
+ package com.swmansion.worklets;
2
+
3
+ import androidx.annotation.OptIn;
4
+ import com.facebook.jni.HybridData;
5
+ import com.facebook.proguard.annotations.DoNotStrip;
6
+ import com.facebook.react.bridge.LifecycleEventListener;
7
+ import com.facebook.react.bridge.ReactApplicationContext;
8
+ import com.facebook.react.bridge.ReactMethod;
9
+ import com.facebook.react.bridge.queue.MessageQueueThread;
10
+ import com.facebook.react.common.annotations.FrameworkAPI;
11
+ import com.facebook.react.module.annotations.ReactModule;
12
+ import com.facebook.react.turbomodule.core.CallInvokerHolderImpl;
13
+ import com.facebook.soloader.SoLoader;
14
+ import java.util.Objects;
15
+
16
+ /**
17
+ * @noinspection JavaJniMissingFunction
18
+ */
19
+ @ReactModule(name = WorkletsModule.NAME)
20
+ public class WorkletsModule extends NativeWorkletsModuleSpec implements LifecycleEventListener {
21
+ static {
22
+ SoLoader.loadLibrary("worklets");
23
+ }
24
+
25
+ @DoNotStrip
26
+ @SuppressWarnings("unused")
27
+ private HybridData mHybridData;
28
+
29
+ @SuppressWarnings("unused")
30
+ protected HybridData getHybridData() {
31
+ return mHybridData;
32
+ }
33
+
34
+ private final WorkletsMessageQueueThread mMessageQueueThread = new WorkletsMessageQueueThread();
35
+ private final AndroidUIScheduler mAndroidUIScheduler;
36
+ private final AnimationFrameQueue mAnimationFrameQueue;
37
+ private boolean mSlowAnimationsEnabled;
38
+
39
+ @OptIn(markerClass = FrameworkAPI.class)
40
+ private native HybridData initHybrid(
41
+ long jsContext,
42
+ String valueUnpackerCode,
43
+ MessageQueueThread messageQueueThread,
44
+ CallInvokerHolderImpl jsCallInvokerHolder,
45
+ AndroidUIScheduler androidUIScheduler);
46
+
47
+ public WorkletsModule(ReactApplicationContext reactContext) {
48
+ super(reactContext);
49
+ reactContext.assertOnJSQueueThread();
50
+ mAndroidUIScheduler = new AndroidUIScheduler(reactContext);
51
+ mAnimationFrameQueue = new AnimationFrameQueue(reactContext);
52
+ }
53
+
54
+ @OptIn(markerClass = FrameworkAPI.class)
55
+ @ReactMethod(isBlockingSynchronousMethod = true)
56
+ public boolean installTurboModule(String valueUnpackerCode) {
57
+ var context = getReactApplicationContext();
58
+ context.assertOnJSQueueThread();
59
+
60
+ var jsContext = Objects.requireNonNull(context.getJavaScriptContextHolder()).get();
61
+ var jsCallInvokerHolder = JSCallInvokerResolver.getJSCallInvokerHolder(context);
62
+
63
+ mHybridData =
64
+ initHybrid(
65
+ jsContext,
66
+ valueUnpackerCode,
67
+ mMessageQueueThread,
68
+ jsCallInvokerHolder,
69
+ mAndroidUIScheduler);
70
+ return true;
71
+ }
72
+
73
+ public void requestAnimationFrame(AnimationFrameCallback animationFrameCallback) {
74
+ mAnimationFrameQueue.requestAnimationFrame(animationFrameCallback);
75
+ }
76
+
77
+ public void toggleSlowAnimations() {
78
+ final int ANIMATIONS_DRAG_FACTOR = 10;
79
+ mSlowAnimationsEnabled = !mSlowAnimationsEnabled;
80
+ mAnimationFrameQueue.enableSlowAnimations(mSlowAnimationsEnabled, ANIMATIONS_DRAG_FACTOR);
81
+ }
82
+
83
+ public void invalidate() {
84
+ // We have to destroy extra runtimes when invalidate is called. If we clean
85
+ // it up later instead there's a chance the runtime will retain references
86
+ // to invalidated memory and will crash on its destruction.
87
+ invalidateCpp();
88
+
89
+ mAndroidUIScheduler.deactivate();
90
+ }
91
+
92
+ private native void invalidateCpp();
93
+
94
+ @Override
95
+ public void onHostResume() {
96
+ mAnimationFrameQueue.resume();
97
+ }
98
+
99
+ @Override
100
+ public void onHostPause() {
101
+ mAnimationFrameQueue.pause();
102
+ }
103
+
104
+ @Override
105
+ public void onHostDestroy() {}
106
+ }
@@ -0,0 +1,49 @@
1
+ package com.swmansion.worklets;
2
+
3
+ import androidx.annotation.NonNull;
4
+ import com.facebook.react.BaseReactPackage;
5
+ import com.facebook.react.ReactPackage;
6
+ import com.facebook.react.bridge.NativeModule;
7
+ import com.facebook.react.bridge.ReactApplicationContext;
8
+ import com.facebook.react.module.annotations.ReactModule;
9
+ import com.facebook.react.module.annotations.ReactModuleList;
10
+ import com.facebook.react.module.model.ReactModuleInfo;
11
+ import com.facebook.react.module.model.ReactModuleInfoProvider;
12
+ import java.util.HashMap;
13
+ import java.util.Map;
14
+ import java.util.Objects;
15
+
16
+ @ReactModuleList(nativeModules = {WorkletsModule.class})
17
+ public class WorkletsPackage extends BaseReactPackage implements ReactPackage {
18
+ @Override
19
+ public NativeModule getModule(
20
+ @NonNull String name, @NonNull ReactApplicationContext reactContext) {
21
+ return switch (name) {
22
+ case WorkletsModule.NAME -> new WorkletsModule(reactContext);
23
+ default -> null;
24
+ };
25
+ }
26
+
27
+ @Override
28
+ public ReactModuleInfoProvider getReactModuleInfoProvider() {
29
+ Class<? extends NativeModule>[] moduleList = new Class[] {WorkletsModule.class};
30
+
31
+ final Map<String, ReactModuleInfo> reactModuleInfoMap = new HashMap<>();
32
+ for (Class<? extends NativeModule> moduleClass : moduleList) {
33
+ ReactModule reactModule =
34
+ Objects.requireNonNull(moduleClass.getAnnotation(ReactModule.class));
35
+
36
+ reactModuleInfoMap.put(
37
+ reactModule.name(),
38
+ new ReactModuleInfo(
39
+ reactModule.name(),
40
+ moduleClass.getName(),
41
+ reactModule.canOverrideExistingModule(),
42
+ reactModule.needsEagerInit(),
43
+ reactModule.isCxxModule(),
44
+ BuildConfig.IS_NEW_ARCHITECTURE_ENABLED));
45
+ }
46
+
47
+ return () -> reactModuleInfoMap;
48
+ }
49
+ }
@@ -0,0 +1,26 @@
1
+ package com.swmansion.worklets;
2
+
3
+ import com.facebook.proguard.annotations.DoNotStrip;
4
+ import com.facebook.react.bridge.ReactApplicationContext;
5
+ import com.facebook.react.bridge.ReactContextBaseJavaModule;
6
+ import com.facebook.react.bridge.ReactMethod;
7
+ import com.facebook.react.turbomodule.core.interfaces.TurboModule;
8
+ import javax.annotation.Nonnull;
9
+
10
+ public abstract class NativeWorkletsModuleSpec extends ReactContextBaseJavaModule
11
+ implements TurboModule {
12
+ public static final String NAME = "WorkletsModule";
13
+
14
+ public NativeWorkletsModuleSpec(ReactApplicationContext reactContext) {
15
+ super(reactContext);
16
+ }
17
+
18
+ @Override
19
+ public @Nonnull String getName() {
20
+ return NAME;
21
+ }
22
+
23
+ @ReactMethod(isBlockingSynchronousMethod = true)
24
+ @DoNotStrip
25
+ public abstract boolean installTurboModule(String valueUnpackerCode);
26
+ }
@@ -0,0 +1,15 @@
1
+ #if __cplusplus
2
+
3
+ #import <worklets/apple/WorkletsDisplayLink.h>
4
+ #import <functional>
5
+
6
+ @interface AnimationFrameQueue : NSObject
7
+
8
+ - (void)requestAnimationFrame:(std::function<void(double)>)callback;
9
+ - (void)executeQueue:(WorkletsDisplayLink *)displayLink;
10
+
11
+ - (void)invalidate;
12
+
13
+ @end
14
+
15
+ #endif // __cplusplus
@@ -0,0 +1,81 @@
1
+ #import <worklets/apple/AnimationFrameQueue.h>
2
+ #import <worklets/apple/AssertJavaScriptQueue.h>
3
+ #import <worklets/apple/AssertTurboModuleManagerQueue.h>
4
+ #import <worklets/apple/SlowAnimations.h>
5
+
6
+ #import <React/RCTAssert.h>
7
+
8
+ @implementation AnimationFrameQueue {
9
+ /* DisplayLink is thread safe. */
10
+ WorkletsDisplayLink *displayLink_;
11
+ std::vector<std::function<void(double)>> frameCallbacks_;
12
+ std::mutex callbacksMutex_;
13
+ }
14
+
15
+ typedef void (^AnimationFrameCallback)(WorkletsDisplayLink *displayLink);
16
+
17
+ #pragma mark-- public
18
+
19
+ - (instancetype)init
20
+ {
21
+ AssertJavaScriptQueue();
22
+ displayLink_ = [WorkletsDisplayLink displayLinkWithTarget:self selector:@selector(executeQueue:)];
23
+ #if TARGET_OS_OSX
24
+ // nothing
25
+ #else // TARGET_OS_OSX
26
+ displayLink_.preferredFramesPerSecond = 120; // will fallback to 60 fps for devices without Pro Motion display
27
+ #endif // TARGET_OS_OSX
28
+ [displayLink_ setPaused:TRUE];
29
+ [displayLink_ addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
30
+ return self;
31
+ }
32
+
33
+ - (void)requestAnimationFrame:(std::function<void(double)>)callback
34
+ {
35
+ {
36
+ std::lock_guard<std::mutex> lock(callbacksMutex_);
37
+ frameCallbacks_.push_back(callback);
38
+ }
39
+ [self scheduleQueueExecution];
40
+ }
41
+
42
+ - (void)invalidate
43
+ {
44
+ AssertTurboModuleManagerQueue();
45
+ [displayLink_ invalidate];
46
+ }
47
+
48
+ #pragma mark-- private
49
+
50
+ - (void)scheduleQueueExecution
51
+ {
52
+ [displayLink_ setPaused:FALSE];
53
+ }
54
+
55
+ - (void)executeQueue:(WorkletsDisplayLink *)displayLink
56
+ {
57
+ RCTAssertMainQueue();
58
+
59
+ auto frameCallbacks = [self pullCallbacks];
60
+ [displayLink_ setPaused:TRUE];
61
+
62
+ #if TARGET_OS_OSX
63
+ auto targetTimestamp = displayLink.timestamp + displayLink.duration;
64
+ #else // TARGET_OS_OSX
65
+ auto targetTimestamp = displayLink.targetTimestamp;
66
+ #endif // TARGET_OS_OSX
67
+ targetTimestamp = worklets::calculateTimestampWithSlowAnimations(targetTimestamp);
68
+
69
+ for (const auto &callback : frameCallbacks) {
70
+ callback(targetTimestamp);
71
+ }
72
+ }
73
+
74
+ - (std::vector<std::function<void(double)>>)pullCallbacks
75
+ {
76
+ RCTAssertMainQueue();
77
+ std::lock_guard<std::mutex> lock(callbacksMutex_);
78
+ return std::move(frameCallbacks_);
79
+ }
80
+
81
+ @end
@@ -0,0 +1,14 @@
1
+ #import <react/debug/react_native_assert.h>
2
+
3
+ // Copied from RCTJSThreadManager.mm
4
+ static NSString *const RCTJSThreadName = @"com.facebook.react.runtime.JavaScript";
5
+
6
+ static BOOL IsJavaScriptQueue()
7
+ {
8
+ return [NSThread.currentThread.name isEqualToString:RCTJSThreadName];
9
+ }
10
+
11
+ static void AssertJavaScriptQueue()
12
+ {
13
+ react_native_assert(IsJavaScriptQueue() && "This function must be called on the JavaScript queue");
14
+ }
@@ -0,0 +1,16 @@
1
+ #import <react/debug/react_native_assert.h>
2
+
3
+ constexpr auto turboModuleManagerQueueLabel =
4
+ "com.meta.react.turbomodulemanager.queue";
5
+
6
+ static bool IsTurboModuleManagerQueue() {
7
+ const auto currentQueueLabel =
8
+ dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL);
9
+ return strcmp(currentQueueLabel, turboModuleManagerQueueLabel) == 0;
10
+ }
11
+
12
+ static void AssertTurboModuleManagerQueue() {
13
+ react_native_assert(
14
+ IsTurboModuleManagerQueue() &&
15
+ "This function must be called on the TurboModuleManager queue");
16
+ }
@@ -0,0 +1,14 @@
1
+ #import <worklets/Tools/UIScheduler.h>
2
+
3
+ namespace worklets {
4
+
5
+ using namespace facebook;
6
+ using namespace react;
7
+ using namespace worklets;
8
+
9
+ class IOSUIScheduler : public UIScheduler {
10
+ public:
11
+ void scheduleOnUI(std::function<void()> job) override;
12
+ };
13
+
14
+ } // namespace worklets
@@ -0,0 +1,24 @@
1
+ #import <worklets/apple/IOSUIScheduler.h>
2
+
3
+ namespace worklets {
4
+
5
+ using namespace facebook;
6
+ using namespace react;
7
+
8
+ void IOSUIScheduler::scheduleOnUI(std::function<void()> job)
9
+ {
10
+ if ([NSThread isMainThread]) {
11
+ job();
12
+ return;
13
+ }
14
+
15
+ UIScheduler::scheduleOnUI(job);
16
+
17
+ if (!scheduledOnUI_) {
18
+ dispatch_async(dispatch_get_main_queue(), ^{
19
+ triggerUI();
20
+ });
21
+ }
22
+ }
23
+
24
+ } // namespace worklets
@@ -0,0 +1,31 @@
1
+ #import <Foundation/Foundation.h>
2
+ #import <worklets/Tools/PlatformLogger.h>
3
+
4
+ namespace worklets {
5
+
6
+ void PlatformLogger::log(const char *str)
7
+ {
8
+ NSLog(@"%@", [NSString stringWithCString:str encoding:[NSString defaultCStringEncoding]]);
9
+ }
10
+
11
+ void PlatformLogger::log(const std::string &str)
12
+ {
13
+ log(str.c_str());
14
+ }
15
+
16
+ void PlatformLogger::log(const double d)
17
+ {
18
+ NSLog(@"%lf", d);
19
+ }
20
+
21
+ void PlatformLogger::log(const int i)
22
+ {
23
+ NSLog(@"%i", i);
24
+ }
25
+
26
+ void PlatformLogger::log(const bool b)
27
+ {
28
+ log(b ? "true" : "false");
29
+ }
30
+
31
+ } // namespace worklets
@@ -0,0 +1,8 @@
1
+ #import <Foundation/Foundation.h>
2
+
3
+ namespace worklets {
4
+
5
+ CGFloat getUIAnimationDragCoefficient(void);
6
+ CFTimeInterval calculateTimestampWithSlowAnimations(CFTimeInterval currentTimestamp);
7
+
8
+ } // namespace worklets
@@ -0,0 +1,47 @@
1
+ #import <QuartzCore/QuartzCore.h>
2
+
3
+ #import <worklets/apple/SlowAnimations.h>
4
+
5
+ #if TARGET_IPHONE_SIMULATOR
6
+ #import <dlfcn.h>
7
+ #endif
8
+
9
+ namespace worklets {
10
+
11
+ CGFloat getUIAnimationDragCoefficient(void)
12
+ {
13
+ static float (*UIAnimationDragCoefficient)(void) = NULL;
14
+ #if TARGET_IPHONE_SIMULATOR
15
+ static dispatch_once_t onceToken;
16
+ dispatch_once(&onceToken, ^{
17
+ UIAnimationDragCoefficient = (float (*)(void))dlsym(RTLD_DEFAULT, "UIAnimationDragCoefficient");
18
+ });
19
+ #endif
20
+ return UIAnimationDragCoefficient ? UIAnimationDragCoefficient() : 1.f;
21
+ }
22
+
23
+ CFTimeInterval calculateTimestampWithSlowAnimations(CFTimeInterval currentTimestamp)
24
+ {
25
+ static const auto MILLISECONDS_IN_SECOND = 1000;
26
+ #if TARGET_IPHONE_SIMULATOR
27
+ static CFTimeInterval dragCoefChangedTimestamp = CACurrentMediaTime();
28
+ static CGFloat previousDragCoef = getUIAnimationDragCoefficient();
29
+
30
+ const CGFloat dragCoef = getUIAnimationDragCoefficient();
31
+ if (previousDragCoef != dragCoef) {
32
+ previousDragCoef = dragCoef;
33
+ dragCoefChangedTimestamp = CACurrentMediaTime();
34
+ }
35
+
36
+ const bool areSlowAnimationsEnabled = dragCoef != 1.f;
37
+ if (areSlowAnimationsEnabled) {
38
+ currentTimestamp = (dragCoefChangedTimestamp + (currentTimestamp - dragCoefChangedTimestamp) / dragCoef);
39
+ }
40
+ currentTimestamp *= MILLISECONDS_IN_SECOND;
41
+ return currentTimestamp;
42
+ #else // TARGET_IPHONE_SIMULATOR
43
+ return currentTimestamp;
44
+ #endif // TARGET_IPHONE_SIMULATOR
45
+ }
46
+
47
+ } // namespace worklets
@@ -0,0 +1,21 @@
1
+ #if TARGET_OS_OSX
2
+
3
+ #ifdef __cplusplus
4
+ extern "C" {
5
+ #endif // __cplusplus
6
+
7
+ #import <React/RCTPlatformDisplayLink.h>
8
+
9
+ #ifdef __cplusplus
10
+ }
11
+ #endif // __cplusplus
12
+
13
+ typedef RCTPlatformDisplayLink WorkletsDisplayLink;
14
+
15
+ #else // TARGET_OS_OSX
16
+
17
+ #import <QuartzCore/CADisplayLink.h>
18
+
19
+ typedef CADisplayLink WorkletsDisplayLink;
20
+
21
+ #endif // TARGET_OS_OSX
@@ -0,0 +1,16 @@
1
+ #pragma once
2
+
3
+ #import <Foundation/Foundation.h>
4
+ #import <React/RCTMessageThread.h>
5
+
6
+ namespace facebook {
7
+ namespace react {
8
+
9
+ class WorkletsMessageThread : public RCTMessageThread {
10
+ public:
11
+ using RCTMessageThread::RCTMessageThread;
12
+ virtual void quitSynchronous() override;
13
+ };
14
+
15
+ } // namespace react
16
+ } // namespace facebook
@@ -0,0 +1,32 @@
1
+ #import <worklets/apple/AssertJavaScriptQueue.h>
2
+ #import <worklets/apple/WorkletsMessageThread.h>
3
+
4
+ namespace facebook {
5
+ namespace react {
6
+
7
+ // Essentially the same as RCTMessageThread, but with public fields.
8
+ struct WorkletsMessageThreadPublic {
9
+ // I don't know why we need three vtables (if you know then feel free to explain it instead of this message),
10
+ // but this is what makes the casts in quitSynchronous() work correctly.
11
+ void *vtable1;
12
+ void *vtable2;
13
+ void *vtable3;
14
+ CFRunLoopRef m_cfRunLoop;
15
+ RCTJavaScriptCompleteBlock m_errorBlock;
16
+ std::atomic_bool m_shutdown;
17
+ };
18
+
19
+ // We need to prevent any new code from being executed on the thread as there
20
+ // is an assertion for that in the destructor of RCTMessageThread, but we have
21
+ // to override quitSynchronous() as it would quit the main looper and freeze
22
+ // the app.
23
+ void WorkletsMessageThread::quitSynchronous()
24
+ {
25
+ AssertJavaScriptQueue();
26
+ RCTMessageThread *rctThread = static_cast<RCTMessageThread *>(this);
27
+ WorkletsMessageThreadPublic *rctThreadPublic = reinterpret_cast<WorkletsMessageThreadPublic *>(rctThread);
28
+ rctThreadPublic->m_shutdown = true;
29
+ }
30
+
31
+ } // namespace react
32
+ } // namespace facebook
@@ -0,0 +1,10 @@
1
+ #import <React/RCTCallInvokerModule.h>
2
+ #import <React/RCTEventEmitter.h>
3
+
4
+ #import <worklets/NativeModules/WorkletsModuleProxy.h>
5
+
6
+ @interface WorkletsModule : RCTEventEmitter <RCTCallInvokerModule>
7
+
8
+ - (std::shared_ptr<worklets::WorkletsModuleProxy>)getWorkletsModuleProxy;
9
+
10
+ @end
@@ -0,0 +1,85 @@
1
+ #import <worklets/Tools/SingleInstanceChecker.h>
2
+ #import <worklets/WorkletRuntime/RNRuntimeWorkletDecorator.h>
3
+ #import <worklets/apple/AnimationFrameQueue.h>
4
+ #import <worklets/apple/AssertJavaScriptQueue.h>
5
+ #import <worklets/apple/AssertTurboModuleManagerQueue.h>
6
+ #import <worklets/apple/IOSUIScheduler.h>
7
+ #import <worklets/apple/WorkletsMessageThread.h>
8
+ #import <worklets/apple/WorkletsModule.h>
9
+
10
+ #import <React/RCTCallInvoker.h>
11
+
12
+ using worklets::RNRuntimeWorkletDecorator;
13
+ using worklets::WorkletsModuleProxy;
14
+
15
+ @interface RCTBridge (JSIRuntime)
16
+ - (void *)runtime;
17
+ @end
18
+
19
+ @implementation WorkletsModule {
20
+ AnimationFrameQueue *animationFrameQueue_;
21
+ std::shared_ptr<WorkletsModuleProxy> workletsModuleProxy_;
22
+ #ifndef NDEBUG
23
+ worklets::SingleInstanceChecker<WorkletsModule> singleInstanceChecker_;
24
+ #endif // NDEBUG
25
+ }
26
+
27
+ - (std::shared_ptr<WorkletsModuleProxy>)getWorkletsModuleProxy
28
+ {
29
+ AssertJavaScriptQueue();
30
+ return workletsModuleProxy_;
31
+ }
32
+
33
+ @synthesize callInvoker = _callInvoker;
34
+
35
+ RCT_EXPORT_MODULE(WorkletsModule);
36
+
37
+ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(installTurboModule : (nonnull NSString *)valueUnpackerCode)
38
+ {
39
+ AssertJavaScriptQueue();
40
+
41
+ react_native_assert(self.bridge != nullptr);
42
+ react_native_assert(self.bridge.runtime != nullptr);
43
+ jsi::Runtime &rnRuntime = *reinterpret_cast<facebook::jsi::Runtime *>(self.bridge.runtime);
44
+
45
+ auto jsQueue = std::make_shared<WorkletsMessageThread>([NSRunLoop currentRunLoop], ^(NSError *error) {
46
+ throw error;
47
+ });
48
+
49
+ std::string valueUnpackerCodeStr = [valueUnpackerCode UTF8String];
50
+ auto jsCallInvoker = _callInvoker.callInvoker;
51
+ auto jsScheduler = std::make_shared<worklets::JSScheduler>(rnRuntime, jsCallInvoker);
52
+ auto uiScheduler = std::make_shared<worklets::IOSUIScheduler>();
53
+ animationFrameQueue_ = [AnimationFrameQueue new];
54
+ auto forwardedRequestAnimationFrame = std::function<void(std::function<void(const double)>)>(
55
+ [animationFrameQueue = animationFrameQueue_](std::function<void(const double)> callback) {
56
+ [animationFrameQueue requestAnimationFrame:callback];
57
+ });
58
+ workletsModuleProxy_ = std::make_shared<WorkletsModuleProxy>(
59
+ rnRuntime,
60
+ valueUnpackerCodeStr,
61
+ jsQueue,
62
+ jsCallInvoker,
63
+ jsScheduler,
64
+ uiScheduler,
65
+ std::move(forwardedRequestAnimationFrame));
66
+ RNRuntimeWorkletDecorator::decorate(rnRuntime, workletsModuleProxy_);
67
+
68
+ return @YES;
69
+ }
70
+
71
+ - (void)invalidate
72
+ {
73
+ AssertTurboModuleManagerQueue();
74
+
75
+ [animationFrameQueue_ invalidate];
76
+
77
+ // We have to destroy extra runtimes when invalidate is called. If we clean
78
+ // it up later instead there's a chance the runtime will retain references
79
+ // to invalidated memory and will crash on destruction.
80
+ workletsModuleProxy_.reset();
81
+
82
+ [super invalidate];
83
+ }
84
+
85
+ @end