@shopify/react-native-skia 0.1.121 → 0.1.124

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 (144) hide show
  1. package/android/CMakeLists.txt +3 -1
  2. package/android/cpp/jni/JniSkiaDrawView.cpp +14 -71
  3. package/android/cpp/jni/JniSkiaManager.cpp +1 -1
  4. package/android/cpp/jni/include/JniSkiaDrawView.h +18 -22
  5. package/android/cpp/jni/include/JniSkiaManager.h +4 -4
  6. package/android/cpp/rnskia-android/RNSkDrawViewImpl.cpp +68 -0
  7. package/android/cpp/rnskia-android/RNSkDrawViewImpl.h +48 -0
  8. package/android/cpp/{jni/include/JniPlatformContextWrapper.h → rnskia-android/RNSkPlatformContextImpl.h} +4 -4
  9. package/android/cpp/{jni → rnskia-android}/SkiaOpenGLRenderer.cpp +39 -54
  10. package/android/cpp/{jni/include → rnskia-android}/SkiaOpenGLRenderer.h +2 -31
  11. package/android/src/main/java/com/shopify/reactnative/skia/RNSkiaViewManager.java +1 -1
  12. package/android/src/main/java/com/shopify/reactnative/skia/SkiaDrawView.java +21 -28
  13. package/cpp/api/JsiSkApi.h +2 -0
  14. package/cpp/api/JsiSkColor.h +49 -0
  15. package/cpp/api/JsiSkPath.h +31 -2
  16. package/cpp/api/JsiSkPathFactory.h +96 -1
  17. package/cpp/api/third_party/CSSColorParser.h +324 -0
  18. package/cpp/rnskia/RNSkAnimation.h +3 -8
  19. package/cpp/rnskia/RNSkDrawView.cpp +84 -126
  20. package/cpp/rnskia/RNSkDrawView.h +7 -37
  21. package/cpp/rnskia/RNSkJsiViewApi.h +8 -5
  22. package/cpp/rnskia/RNSkManager.cpp +2 -2
  23. package/cpp/rnskia/RNSkManager.h +2 -2
  24. package/cpp/rnskia/RNSkPlatformContext.h +1 -1
  25. package/cpp/rnskia/RNSkValueApi.h +6 -2
  26. package/cpp/rnskia/values/RNSkClockValue.h +21 -13
  27. package/cpp/rnskia/values/RNSkDerivedValue.h +13 -6
  28. package/cpp/rnskia/values/RNSkReadonlyValue.h +17 -16
  29. package/cpp/rnskia/values/RNSkValue.h +8 -3
  30. package/cpp/utils/RNSkTimingInfo.h +13 -1
  31. package/ios/RNSkia-iOS/RNSkDrawViewImpl.h +8 -10
  32. package/ios/RNSkia-iOS/RNSkDrawViewImpl.mm +25 -10
  33. package/ios/RNSkia-iOS/SkiaDrawView.mm +21 -16
  34. package/lib/commonjs/renderer/Canvas.js +17 -8
  35. package/lib/commonjs/renderer/Canvas.js.map +1 -1
  36. package/lib/commonjs/renderer/components/Paint.js +1 -1
  37. package/lib/commonjs/renderer/components/Paint.js.map +1 -1
  38. package/lib/commonjs/renderer/components/colorFilters/Lerp.js +1 -1
  39. package/lib/commonjs/renderer/components/colorFilters/Lerp.js.map +1 -1
  40. package/lib/commonjs/renderer/components/shaders/Shader.js +2 -2
  41. package/lib/commonjs/renderer/components/shaders/Shader.js.map +1 -1
  42. package/lib/commonjs/renderer/components/shapes/Path.js +10 -2
  43. package/lib/commonjs/renderer/components/shapes/Path.js.map +1 -1
  44. package/lib/commonjs/renderer/nodes/Node.js +3 -3
  45. package/lib/commonjs/renderer/nodes/Node.js.map +1 -1
  46. package/lib/commonjs/renderer/processors/Circles.js +3 -2
  47. package/lib/commonjs/renderer/processors/Circles.js.map +1 -1
  48. package/lib/commonjs/renderer/processors/Font.js +1 -1
  49. package/lib/commonjs/renderer/processors/Font.js.map +1 -1
  50. package/lib/commonjs/renderer/processors/Paint.js +6 -1
  51. package/lib/commonjs/renderer/processors/Paint.js.map +1 -1
  52. package/lib/commonjs/renderer/processors/Rects.js +6 -6
  53. package/lib/commonjs/renderer/processors/Rects.js.map +1 -1
  54. package/lib/commonjs/skia/Color.js +3 -25
  55. package/lib/commonjs/skia/Color.js.map +1 -1
  56. package/lib/commonjs/skia/Image/Image.js.map +1 -1
  57. package/lib/commonjs/skia/ImageFilter/ImageFilterFactory.js.map +1 -1
  58. package/lib/commonjs/skia/Paint/Paint.js +13 -1
  59. package/lib/commonjs/skia/Paint/Paint.js.map +1 -1
  60. package/lib/commonjs/skia/Paint/usePaint.js +2 -4
  61. package/lib/commonjs/skia/Paint/usePaint.js.map +1 -1
  62. package/lib/commonjs/skia/Path/Path.js +13 -1
  63. package/lib/commonjs/skia/Path/Path.js.map +1 -1
  64. package/lib/commonjs/skia/Shader/Shader.js.map +1 -1
  65. package/lib/commonjs/skia/Skia.js +43 -3
  66. package/lib/commonjs/skia/Skia.js.map +1 -1
  67. package/lib/commonjs/values/animation/timing/functions/getResolvedParams.js +3 -3
  68. package/lib/commonjs/values/animation/timing/functions/getResolvedParams.js.map +1 -1
  69. package/lib/module/renderer/Canvas.js +12 -6
  70. package/lib/module/renderer/Canvas.js.map +1 -1
  71. package/lib/module/renderer/components/Paint.js +2 -2
  72. package/lib/module/renderer/components/Paint.js.map +1 -1
  73. package/lib/module/renderer/components/colorFilters/Lerp.js +1 -1
  74. package/lib/module/renderer/components/colorFilters/Lerp.js.map +1 -1
  75. package/lib/module/renderer/components/shaders/Shader.js +3 -2
  76. package/lib/module/renderer/components/shaders/Shader.js.map +1 -1
  77. package/lib/module/renderer/components/shapes/Path.js +10 -3
  78. package/lib/module/renderer/components/shapes/Path.js.map +1 -1
  79. package/lib/module/renderer/nodes/Node.js +3 -3
  80. package/lib/module/renderer/nodes/Node.js.map +1 -1
  81. package/lib/module/renderer/processors/Circles.js +3 -2
  82. package/lib/module/renderer/processors/Circles.js.map +1 -1
  83. package/lib/module/renderer/processors/Font.js +1 -1
  84. package/lib/module/renderer/processors/Font.js.map +1 -1
  85. package/lib/module/renderer/processors/Paint.js +6 -1
  86. package/lib/module/renderer/processors/Paint.js.map +1 -1
  87. package/lib/module/renderer/processors/Rects.js +5 -6
  88. package/lib/module/renderer/processors/Rects.js.map +1 -1
  89. package/lib/module/skia/Color.js +2 -21
  90. package/lib/module/skia/Color.js.map +1 -1
  91. package/lib/module/skia/Image/Image.js.map +1 -1
  92. package/lib/module/skia/ImageFilter/ImageFilterFactory.js.map +1 -1
  93. package/lib/module/skia/Paint/Paint.js +6 -0
  94. package/lib/module/skia/Paint/Paint.js.map +1 -1
  95. package/lib/module/skia/Paint/usePaint.js +2 -3
  96. package/lib/module/skia/Paint/usePaint.js.map +1 -1
  97. package/lib/module/skia/Path/Path.js +11 -0
  98. package/lib/module/skia/Path/Path.js.map +1 -1
  99. package/lib/module/skia/Shader/Shader.js.map +1 -1
  100. package/lib/module/skia/Skia.js +45 -2
  101. package/lib/module/skia/Skia.js.map +1 -1
  102. package/lib/module/values/animation/timing/functions/getResolvedParams.js +3 -3
  103. package/lib/module/values/animation/timing/functions/getResolvedParams.js.map +1 -1
  104. package/lib/typescript/src/renderer/Canvas.d.ts +6 -0
  105. package/lib/typescript/src/renderer/components/shapes/Path.d.ts +3 -1
  106. package/lib/typescript/src/renderer/processors/Paint.d.ts +2 -1
  107. package/lib/typescript/src/skia/Color.d.ts +0 -1
  108. package/lib/typescript/src/skia/Image/Image.d.ts +3 -3
  109. package/lib/typescript/src/skia/ImageFilter/ImageFilterFactory.d.ts +2 -2
  110. package/lib/typescript/src/skia/Paint/Paint.d.ts +3 -2
  111. package/lib/typescript/src/skia/Path/Path.d.ts +13 -0
  112. package/lib/typescript/src/skia/Path/PathFactory.d.ts +7 -1
  113. package/lib/typescript/src/skia/Picture/Picture.d.ts +2 -2
  114. package/lib/typescript/src/skia/RuntimeEffect/RuntimeEffect.d.ts +3 -3
  115. package/lib/typescript/src/skia/Shader/Shader.d.ts +2 -2
  116. package/lib/typescript/src/skia/Shader/ShaderFactory.d.ts +9 -9
  117. package/lib/typescript/src/skia/Skia.d.ts +5 -3
  118. package/lib/typescript/src/values/animation/types.d.ts +5 -5
  119. package/package.json +1 -1
  120. package/scripts/install-npm.js +1 -1
  121. package/src/renderer/Canvas.tsx +13 -6
  122. package/src/renderer/components/Paint.tsx +2 -2
  123. package/src/renderer/components/colorFilters/Lerp.tsx +1 -1
  124. package/src/renderer/components/shaders/Shader.tsx +1 -1
  125. package/src/renderer/components/shapes/Path.tsx +12 -4
  126. package/src/renderer/nodes/Node.ts +3 -3
  127. package/src/renderer/processors/Circles.ts +2 -1
  128. package/src/renderer/processors/Font.ts +1 -1
  129. package/src/renderer/processors/Paint.ts +5 -0
  130. package/src/renderer/processors/Rects.ts +3 -2
  131. package/src/skia/Color.ts +3 -20
  132. package/src/skia/Image/Image.ts +3 -3
  133. package/src/skia/ImageFilter/ImageFilterFactory.ts +2 -2
  134. package/src/skia/Paint/Paint.ts +9 -2
  135. package/src/skia/Paint/usePaint.ts +2 -4
  136. package/src/skia/Path/Path.ts +16 -0
  137. package/src/skia/Path/PathFactory.ts +8 -1
  138. package/src/skia/Picture/Picture.ts +2 -2
  139. package/src/skia/RuntimeEffect/RuntimeEffect.ts +4 -4
  140. package/src/skia/Shader/Shader.ts +2 -2
  141. package/src/skia/Shader/ShaderFactory.ts +9 -9
  142. package/src/skia/Skia.ts +47 -3
  143. package/src/values/animation/timing/functions/getResolvedParams.ts +2 -2
  144. package/src/values/animation/types.ts +5 -5
@@ -15,7 +15,7 @@ using namespace facebook;
15
15
  /**
16
16
  Implements an animation that can be used to drive other values
17
17
  */
18
- class RNSkAnimation : public RNSkClockValue, public std::enable_shared_from_this<RNSkAnimation>
18
+ class RNSkAnimation : public RNSkClockValue
19
19
  {
20
20
 
21
21
  public:
@@ -23,8 +23,8 @@ public:
23
23
  size_t identifier,
24
24
  jsi::Runtime& runtime,
25
25
  const jsi::Value *arguments,
26
- size_t count)
27
- : RNSkClockValue(platformContext, identifier, runtime, arguments, count) {
26
+ size_t count) :
27
+ RNSkClockValue(platformContext, identifier, runtime, arguments, count) {
28
28
  // Save the update function
29
29
  _updateFunction = std::make_shared<jsi::Function>(arguments[0].asObject(runtime).asFunction(runtime));
30
30
 
@@ -32,11 +32,6 @@ public:
32
32
  _args[1] = jsi::Value::undefined();
33
33
  }
34
34
 
35
- ~RNSkAnimation() {
36
- // We need to stop/unsubscribe
37
- stopClock();
38
- }
39
-
40
35
  JSI_HOST_FUNCTION(cancel) {
41
36
  stopClock();
42
37
  return jsi::Value::undefined();
@@ -40,31 +40,13 @@ RNSkDrawView::RNSkDrawView(std::shared_ptr<RNSkPlatformContext> context)
40
40
  _platformContext(std::move(context)),
41
41
  _infoObject(std::make_shared<RNSkInfoObject>()),
42
42
  _jsDrawingLock(std::make_shared<std::timed_mutex>()),
43
- _gpuDrawingLock(std::make_shared<std::timed_mutex>())
43
+ _gpuDrawingLock(std::make_shared<std::timed_mutex>()),
44
+ _jsTimingInfo("SKIA/JS"),
45
+ _gpuTimingInfo("SKIA/GPU")
44
46
  {}
45
47
 
46
48
  RNSkDrawView::~RNSkDrawView() {
47
- #if LOG_ALL_DRAWING
48
- RNSkLogger::logToConsole("RNSkDrawView::~RNSkDrawView - %i", getNativeId());
49
- #endif
50
-
51
- _isInvalidated = true;
52
-
53
49
  endDrawingLoop();
54
-
55
- // Wait for the drawing locks
56
- if(!_jsDrawingLock->try_lock_for(1250ms)) {
57
- RNSkLogger::logToConsole("Warning: JS drawing is still locked for native view with id %i", _nativeId);
58
- }
59
-
60
- if(!_gpuDrawingLock->try_lock_for(1250ms)) {
61
- RNSkLogger::logToConsole("Warning: SKIA drawing is still locked for native view with id %i", _nativeId);
62
- }
63
-
64
- onInvalidated();
65
-
66
- _jsDrawingLock = nullptr;
67
- _gpuDrawingLock = nullptr;
68
50
  }
69
51
 
70
52
  void RNSkDrawView::setNativeId(size_t nativeId) {
@@ -84,63 +66,63 @@ void RNSkDrawView::setDrawCallback(std::shared_ptr<jsi::Function> callback) {
84
66
  // Reset timing info
85
67
  _jsTimingInfo.reset();
86
68
  _gpuTimingInfo.reset();
87
- _vsyncTimingInfo.reset();
88
-
89
- // Set up debug font/paints
90
- auto font = SkFont();
91
- font.setSize(14);
92
- auto paint = SkPaint();
93
- paint.setColor(SkColors::kRed);
94
69
 
95
70
  // Create draw drawCallback wrapper
96
71
  _drawCallback = std::make_shared<RNSkDrawCallback>(
97
- [this, paint = std::move(paint), font = std::move(font), callback = std::move(callback)](std::shared_ptr<JsiSkCanvas> canvas, int width,
98
- int height, double timestamp,
99
- std::shared_ptr<RNSkPlatformContext> context) {
100
-
101
- auto runtime = context->getJsRuntime();
102
-
103
- // Update info parameter
104
- _infoObject->beginDrawOperation(width, height, timestamp);
105
-
106
- // Set up arguments array
107
- std::vector<jsi::Value> args(2);
108
- args[0] = jsi::Object::createFromHostObject(*runtime, canvas);
109
- args[1] = jsi::Object::createFromHostObject(*runtime, _infoObject);
110
-
111
- // To be able to call the drawing function we'll wrap it once again
112
- callback->call(*runtime,
113
- static_cast<const jsi::Value *>(args.data()),
114
- (size_t)2);
115
-
116
- // Reset touches
117
- _infoObject->endDrawOperation();
118
-
119
- // Draw debug overlays
120
- if (_showDebugOverlay) {
121
-
122
- // Display average rendering timer
123
- auto jsAvg = _jsTimingInfo.getAverage();
124
- //auto jsFps = _jsTimingInfo.getFps();
125
-
126
- auto gpuAvg = _gpuTimingInfo.getAverage();
127
- //auto gpuFps = _gpuTimingInfo.getFps();
128
-
129
- auto total = jsAvg + gpuAvg;
130
-
131
- //auto vsyncFps = _vsyncTimingInfo.getFps();
132
-
133
- // Build string
134
- std::ostringstream stream;
135
- stream << "js: " << jsAvg << "ms gpu: " << gpuAvg << "ms " << " total: " << total << "ms";
136
- // stream << "js:" << jsAvg << "ms/" << jsFps << "fps " << "gpu:" << gpuAvg << "ms/" <<
137
- // gpuFps << "fps" << " total:" << total << "ms/" << vsyncFps << "fps";
138
-
139
- std::string debugString = stream.str();
140
-
141
- canvas->getCanvas()->drawSimpleText(
142
- debugString.c_str(), debugString.size(), SkTextEncoding::kUTF8, 8,
143
- 18, font, paint);
72
+ [weakSelf = weak_from_this(),
73
+ callback = std::move(callback)](std::shared_ptr<JsiSkCanvas> canvas,
74
+ int width,
75
+ int height,
76
+ double timestamp,
77
+ std::shared_ptr<RNSkPlatformContext> context) {
78
+
79
+ auto self = weakSelf.lock();
80
+ if(self) {
81
+ auto runtime = context->getJsRuntime();
82
+
83
+ // Update info parameter
84
+ self->_infoObject->beginDrawOperation(width, height, timestamp);
85
+
86
+ // Set up arguments array
87
+ std::vector<jsi::Value> args(2);
88
+ args[0] = jsi::Object::createFromHostObject(*runtime, canvas);
89
+ args[1] = jsi::Object::createFromHostObject(*runtime, self->_infoObject);
90
+
91
+ // To be able to call the drawing function we'll wrap it once again
92
+ callback->call(*runtime,
93
+ static_cast<const jsi::Value *>(args.data()),
94
+ (size_t)2);
95
+
96
+ // Reset touches
97
+ self->_infoObject->endDrawOperation();
98
+
99
+ // Draw debug overlays
100
+ if (self->_showDebugOverlay) {
101
+
102
+ // Display average rendering timer
103
+ auto jsAvg = self->_jsTimingInfo.getAverage();
104
+ //auto jsFps = _jsTimingInfo.getFps();
105
+
106
+ auto gpuAvg = self->_gpuTimingInfo.getAverage();
107
+ //auto gpuFps = _gpuTimingInfo.getFps();
108
+
109
+ auto total = jsAvg + gpuAvg;
110
+
111
+ // Build string
112
+ std::ostringstream stream;
113
+ stream << "js: " << jsAvg << "ms gpu: " << gpuAvg << "ms " << " total: " << total << "ms";
114
+
115
+ std::string debugString = stream.str();
116
+
117
+ // Set up debug font/paints
118
+ auto font = SkFont();
119
+ font.setSize(14);
120
+ auto paint = SkPaint();
121
+ paint.setColor(SkColors::kRed);
122
+ canvas->getCanvas()->drawSimpleText(
123
+ debugString.c_str(), debugString.size(), SkTextEncoding::kUTF8, 8,
124
+ 18, font, paint);
125
+ }
144
126
  }
145
127
  });
146
128
 
@@ -172,7 +154,7 @@ void RNSkDrawView::drawInCanvas(std::shared_ptr<JsiSkCanvas> canvas,
172
154
 
173
155
  sk_sp<SkImage> RNSkDrawView::makeImageSnapshot(std::shared_ptr<SkRect> bounds) {
174
156
  // Assert width/height
175
- auto surface = SkSurface::MakeRasterN32Premul(getWidth(), getHeight());
157
+ auto surface = SkSurface::MakeRasterN32Premul(getScaledWidth(), getScaledHeight());
176
158
  auto canvas = surface->getCanvas();
177
159
  auto jsiCanvas = std::make_shared<JsiSkCanvas>(_platformContext);
178
160
  jsiCanvas->setCanvas(canvas);
@@ -180,7 +162,7 @@ sk_sp<SkImage> RNSkDrawView::makeImageSnapshot(std::shared_ptr<SkRect> bounds) {
180
162
  milliseconds ms = duration_cast<milliseconds>(
181
163
  system_clock::now().time_since_epoch());
182
164
 
183
- drawInCanvas(jsiCanvas, getWidth(), getHeight(), ms.count() / 1000);
165
+ drawInCanvas(jsiCanvas, getScaledWidth(), getScaledHeight(), ms.count() / 1000);
184
166
 
185
167
  if(bounds != nullptr) {
186
168
  SkIRect b = SkIRect::MakeXYWH(bounds->x(), bounds->y(), bounds->width(), bounds->height());
@@ -196,10 +178,6 @@ void RNSkDrawView::updateTouchState(std::vector<RNSkTouchPoint>&& points) {
196
178
  }
197
179
 
198
180
  void RNSkDrawView::performDraw() {
199
- #if LOG_ALL_DRAWING
200
- RNSkLogger::logToConsole("RNSkDrawView::performDraw - %i", getNativeId());
201
- #endif
202
-
203
181
  // Start timing
204
182
  _jsTimingInfo.beginTiming();
205
183
 
@@ -207,7 +185,7 @@ void RNSkDrawView::performDraw() {
207
185
  // move the actual drawing onto the render thread later
208
186
  SkPictureRecorder recorder;
209
187
  SkRTreeFactory factory;
210
- SkCanvas* canvas = recorder.beginRecording(getWidth(), getHeight(), &factory);
188
+ SkCanvas* canvas = recorder.beginRecording(getScaledWidth(), getScaledHeight(), &factory);
211
189
  _jsiCanvas->setCanvas(canvas);
212
190
 
213
191
  // Get current milliseconds
@@ -216,7 +194,7 @@ void RNSkDrawView::performDraw() {
216
194
 
217
195
  try {
218
196
  // Perform the javascript drawing
219
- drawInCanvas(_jsiCanvas, getWidth(), getHeight(), ms.count() / 1000.0);
197
+ drawInCanvas(_jsiCanvas, getScaledWidth(), getScaledHeight(), ms.count() / 1000.0);
220
198
  } catch(...) {
221
199
  _jsTimingInfo.stopTiming();
222
200
  _jsDrawingLock->unlock();
@@ -234,37 +212,22 @@ void RNSkDrawView::performDraw() {
234
212
  // Post drawing message to the render thread where the picture recorded
235
213
  // will be sent to the GPU/backend for rendering to screen.
236
214
  auto gpuLock = _gpuDrawingLock;
237
- getPlatformContext()->runOnRenderThread([this, p = std::move(p), gpuLock]() {
238
-
239
- if(isInvalidated()) {
240
- gpuLock->unlock();
241
- return;
215
+ _platformContext->runOnRenderThread([weakSelf = weak_from_this(), p = std::move(p), gpuLock]() {
216
+ auto self = weakSelf.lock();
217
+ if (self) {
218
+ // Draw the picture recorded on the real GPU canvas
219
+ self->_gpuTimingInfo.beginTiming();
220
+ self->drawPicture(p);
221
+ self->_gpuTimingInfo.stopTiming();
242
222
  }
243
-
244
- _gpuTimingInfo.beginTiming();
245
-
246
- // Draw the picture recorded on the real GPU canvas
247
- if(_nativeDrawFunc != nullptr) {
248
- #if LOG_ALL_DRAWING
249
- RNSkLogger::logToConsole("RNSkDrawView::drawFrame - %i", getNativeId());
250
- #endif
251
- _nativeDrawFunc(p);
252
- } else {
253
- #if LOG_ALL_DRAWING
254
- RNSkLogger::logToConsole("RNSkDrawView::drawFrame - %i SKIPPING, draw func is null", getNativeId());
255
- #endif
256
- }
257
-
258
- _gpuTimingInfo.stopTiming();
259
-
260
223
  // Unlock GPU drawing
261
224
  gpuLock->unlock();
262
225
  });
263
226
  } else {
264
227
  #ifdef DEBUG
265
- static size_t framesSkipped = 0;
266
- printf("SKIA/GPU: Skipped frames: %lu\n", ++framesSkipped);
228
+ _gpuTimingInfo.markSkipped();
267
229
  #endif
230
+ // Request a new redraw since the last frame was skipped.
268
231
  requestRedraw();
269
232
  }
270
233
 
@@ -280,39 +243,34 @@ void RNSkDrawView::beginDrawingLoop() {
280
243
  if (_drawingLoopId != 0 || _nativeId == 0) {
281
244
  return;
282
245
  }
283
-
284
246
  // Set to zero to avoid calling beginDrawLoop before we return
285
- _drawingLoopId = _platformContext->beginDrawLoop(
286
- _nativeId, std::bind(&RNSkDrawView::drawLoopCallback, this, std::placeholders::_1));
247
+ _drawingLoopId = _platformContext->beginDrawLoop(_nativeId,
248
+ [weakSelf = weak_from_this()](bool invalidated) {
249
+ auto self = weakSelf.lock();
250
+ if(self) {
251
+ self->drawLoopCallback(invalidated);
252
+ }
253
+ });
287
254
  }
288
255
 
289
256
  void RNSkDrawView::drawLoopCallback(bool invalidated) {
290
- if(invalidated) {
291
- _isInvalidated = true;
292
- onInvalidated();
293
- #if LOG_ALL_DRAWING
294
- RNSkLogger::logToConsole("RNSkDrawView::onInvalidated - %i", getNativeId());
295
- #endif
296
- return;
297
- }
298
-
299
257
  if(_redrawRequestCounter > 0 || _drawingMode == RNSkDrawingMode::Continuous) {
300
258
  _redrawRequestCounter = 0;
301
259
 
302
- _vsyncTimingInfo.beginTiming();
303
-
304
260
  // We render on the javascript thread.
305
261
  if(_jsDrawingLock->try_lock()) {
306
- _platformContext->runOnJavascriptThread(std::bind(&RNSkDrawView::performDraw, this));
262
+ _platformContext->runOnJavascriptThread([weakSelf = weak_from_this()](){
263
+ auto self = weakSelf.lock();
264
+ if(self) {
265
+ self->performDraw();
266
+ }
267
+ });
307
268
  } else {
308
269
  #ifdef DEBUG
309
- static size_t framesSkipped = 0;
310
- printf("SKIA/JS: Skipped frames: %lu\n", ++framesSkipped);
270
+ _jsTimingInfo.markSkipped();
311
271
  #endif
312
272
  requestRedraw();
313
273
  }
314
-
315
- _vsyncTimingInfo.stopTiming();
316
274
  }
317
275
  }
318
276
 
@@ -20,8 +20,6 @@
20
20
 
21
21
  #pragma clang diagnostic pop
22
22
 
23
- #define LOG_ALL_DRAWING 0
24
-
25
23
  class SkPicture;
26
24
  class SkRect;
27
25
  class SkImage;
@@ -35,7 +33,7 @@ using RNSkDrawCallback =
35
33
 
36
34
  enum RNSkDrawingMode { Default, Continuous };
37
35
 
38
- class RNSkDrawView {
36
+ class RNSkDrawView: public std::enable_shared_from_this<RNSkDrawView> {
39
37
  public:
40
38
  /**
41
39
  * Constructor
@@ -45,7 +43,7 @@ public:
45
43
  /**
46
44
  Destructor
47
45
  */
48
- ~RNSkDrawView();
46
+ virtual ~RNSkDrawView();
49
47
 
50
48
  /**
51
49
  * Repaints the Skia view using the underlying context and the drawcallback.
@@ -96,33 +94,20 @@ public:
96
94
  sk_sp<SkImage> makeImageSnapshot(std::shared_ptr<SkRect> bounds);
97
95
 
98
96
  protected:
99
- void setNativeDrawFunc(std::function<void(const sk_sp<SkPicture>)> drawFunc) {
100
- if(!_gpuDrawingLock->try_lock_for(250ms)) {
101
- RNSkLogger::logToConsole("Could not lock drawing when clearing drawing function - %i", _nativeId);
102
- }
103
- _nativeDrawFunc = drawFunc;
104
- _gpuDrawingLock->unlock();
105
- }
106
-
107
97
  /**
108
98
  Returns the scaled width of the view
109
99
  */
110
- virtual int getWidth() { return -1; };
100
+ virtual float getScaledWidth() = 0;
111
101
 
112
102
  /**
113
103
  Returns the scaled height of the view
114
104
  */
115
- virtual int getHeight() { return -1; };
116
-
117
- /**
118
- Returns true if the view is invalidated
119
- */
120
- volatile bool isInvalidated() { return _isInvalidated; }
105
+ virtual float getScaledHeight() = 0;
121
106
 
122
107
  /**
123
- Override to be notified on invalidation
108
+ Override to render picture to GPU
124
109
  */
125
- virtual void onInvalidated() {}
110
+ virtual void drawPicture(const sk_sp<SkPicture> picture) = 0;
126
111
 
127
112
  /**
128
113
  * @return The platformcontext
@@ -210,12 +195,7 @@ private:
210
195
  /**
211
196
  Timing information for GPU rendering
212
197
  */
213
- RNSkTimingInfo _gpuTimingInfo;
214
-
215
- /**
216
- Measures vsync framerate
217
- */
218
- RNSkTimingInfo _vsyncTimingInfo;
198
+ RNSkTimingInfo _gpuTimingInfo;
219
199
 
220
200
  /**
221
201
  Redraw queue counter
@@ -227,16 +207,6 @@ private:
227
207
  */
228
208
  size_t _nativeId;
229
209
 
230
- /**
231
- Invalidation flag
232
- */
233
- std::atomic<bool> _isInvalidated = { false };
234
-
235
- /**
236
- Native draw handler
237
- */
238
- std::function<void(const sk_sp<SkPicture>)> _nativeDrawFunc;
239
-
240
210
  };
241
211
 
242
212
  } // namespace RNSkia
@@ -20,7 +20,7 @@ using CallbackInfo = struct CallbackInfo {
20
20
  view = nullptr;
21
21
  }
22
22
  std::shared_ptr<jsi::Function> drawCallback;
23
- RNSkDrawView *view;
23
+ std::shared_ptr<RNSkDrawView> view;
24
24
  };
25
25
 
26
26
  class RNSkJsiViewApi : public JsiHostObject {
@@ -105,7 +105,7 @@ public:
105
105
  sk_sp<SkImage> image;
106
106
  auto info = getEnsuredCallbackInfo(nativeId);
107
107
  if (info->view != nullptr) {
108
- if(count > 1 && !arguments[1].isUndefined() && arguments[1].isNull()) {
108
+ if(count > 1 && !arguments[1].isUndefined() && !arguments[1].isNull()) {
109
109
  auto rect = JsiSkRect::fromValue(runtime, arguments[1]);
110
110
  image = info->view->makeImageSnapshot(rect);
111
111
  } else {
@@ -226,7 +226,7 @@ public:
226
226
  * @param nativeId Id of view to register
227
227
  * @param view View to register
228
228
  */
229
- void registerSkiaDrawView(size_t nativeId, RNSkDrawView *view) {
229
+ void registerSkiaDrawView(size_t nativeId, std::shared_ptr<RNSkDrawView> view) {
230
230
  auto info = getEnsuredCallbackInfo(nativeId);
231
231
  info->view = view;
232
232
  if (info->drawCallback != nullptr) {
@@ -260,15 +260,18 @@ public:
260
260
  a valid view is set, the setDrawCallback method is called on the
261
261
  view (if a valid callback exists).
262
262
  */
263
- void setSkiaDrawView(size_t nativeId, RNSkDrawView *view) {
263
+ void setSkiaDrawView(size_t nativeId, std::shared_ptr<RNSkDrawView> view) {
264
264
  if (_callbackInfos.find(nativeId) == _callbackInfos.end()) {
265
265
  return;
266
266
  }
267
267
  auto info = getEnsuredCallbackInfo(nativeId);
268
- info->view = view;
269
268
  if (view != nullptr && info->drawCallback != nullptr) {
269
+ info->view = view;
270
270
  info->view->setNativeId(nativeId);
271
271
  info->view->setDrawCallback(info->drawCallback);
272
+ } else if(view == nullptr && info->drawCallback != nullptr) {
273
+ info->view->setDrawCallback(nullptr);
274
+ info->view = view;
272
275
  }
273
276
  }
274
277
 
@@ -45,7 +45,7 @@ void RNSkManager::invalidate() {
45
45
  _platformContext->invalidate();
46
46
  }
47
47
 
48
- void RNSkManager::registerSkiaDrawView(size_t nativeId, RNSkDrawView *view) {
48
+ void RNSkManager::registerSkiaDrawView(size_t nativeId, std::shared_ptr<RNSkDrawView> view) {
49
49
  if (!_isInvalidated && _viewApi != nullptr)
50
50
  _viewApi->registerSkiaDrawView(nativeId, view);
51
51
  }
@@ -55,7 +55,7 @@ void RNSkManager::unregisterSkiaDrawView(size_t nativeId) {
55
55
  _viewApi->unregisterSkiaDrawView(nativeId);
56
56
  }
57
57
 
58
- void RNSkManager::setSkiaDrawView(size_t nativeId, RNSkDrawView *view) {
58
+ void RNSkManager::setSkiaDrawView(size_t nativeId, std::shared_ptr<RNSkDrawView> view) {
59
59
  if (!_isInvalidated && _viewApi != nullptr)
60
60
  _viewApi->setSkiaDrawView(nativeId, view);
61
61
  }
@@ -41,7 +41,7 @@ public:
41
41
  * @param nativeId Native view id
42
42
  * @param view View to register
43
43
  */
44
- void registerSkiaDrawView(size_t nativeId, RNSkDrawView *view);
44
+ void registerSkiaDrawView(size_t nativeId, std::shared_ptr<RNSkDrawView> view);
45
45
 
46
46
  /**
47
47
  * Unregisters the RNSkDrawView from the list of registered views
@@ -54,7 +54,7 @@ public:
54
54
  Used when we want to remove a view without unregistering it
55
55
  - this happens typically on iOS.
56
56
  */
57
- void setSkiaDrawView(size_t nativeId, RNSkDrawView *view);
57
+ void setSkiaDrawView(size_t nativeId, std::shared_ptr<RNSkDrawView> view);
58
58
 
59
59
  /**
60
60
  * @return The platform context
@@ -43,7 +43,7 @@ public:
43
43
  /**
44
44
  * Destructor
45
45
  */
46
- ~RNSkPlatformContext() {
46
+ virtual ~RNSkPlatformContext() {
47
47
  invalidate();
48
48
  }
49
49
 
@@ -34,8 +34,12 @@ public:
34
34
  }
35
35
 
36
36
  JSI_HOST_FUNCTION(createDerivedValue) {
37
- return jsi::Object::createFromHostObject(runtime,
38
- std::make_shared<RNSkDerivedValue>(_platformContext, runtime, arguments, count));
37
+ // Creation and initialization is done in two steps to be able to use weak references when setting
38
+ // up dependencies - since weak_from_this needs our instance to be a shared_ptr before calling
39
+ // weak_from_this().
40
+ auto derivedValue = std::make_shared<RNSkDerivedValue>(_platformContext, runtime, arguments, count);
41
+ derivedValue->initializeDependencies(runtime, arguments, count);
42
+ return jsi::Object::createFromHostObject(runtime, derivedValue);
39
43
  }
40
44
 
41
45
  JSI_HOST_FUNCTION(createAnimation) {
@@ -8,7 +8,6 @@
8
8
  #include <algorithm>
9
9
  #include <functional>
10
10
  #include <chrono>
11
- #include <mutex>
12
11
 
13
12
  namespace RNSkia
14
13
  {
@@ -33,12 +32,11 @@ public:
33
32
  size_t count) : RNSkReadonlyValue(platformContext),
34
33
  _runtime(runtime),
35
34
  _identifier(identifier) {
36
-
37
35
  // Start by updating to zero (start value)
38
36
  update(_runtime, static_cast<double>(0));
39
37
  }
40
38
 
41
- ~RNSkClockValue() {
39
+ virtual ~RNSkClockValue() {
42
40
  stopClock();
43
41
  }
44
42
 
@@ -73,8 +71,13 @@ public:
73
71
  _start += timeSinceStop;
74
72
 
75
73
  _state = RNSkClockState::Running;
76
- auto dispatch = std::bind(&RNSkClockValue::notifyUpdate, this, std::placeholders::_1);
77
- getContext()->beginDrawLoop(_identifier, dispatch);
74
+
75
+ getContext()->beginDrawLoop(_identifier, [weakSelf = weak_from_this()](bool invalidated){
76
+ auto self = weakSelf.lock();
77
+ if(self) {
78
+ std::dynamic_pointer_cast<RNSkClockValue>(self)->notifyUpdate(invalidated);
79
+ }
80
+ });
78
81
  }
79
82
 
80
83
  virtual void stopClock() {
@@ -100,15 +103,20 @@ protected:
100
103
  return;
101
104
  }
102
105
 
103
- // Avoid moving on if we are being called after the dtor was started
104
106
  // Ensure we call any updates from the draw loop on the javascript thread
105
107
  getContext()->runOnJavascriptThread(
106
- [this]() {
107
- if(_state == RNSkClockState::Running) {
108
- auto now = std::chrono::high_resolution_clock::now();
109
- auto deltaFromStart = std::chrono::duration_cast<std::chrono::milliseconds>(now - _start).count();
110
- tick(_runtime, static_cast<double>(deltaFromStart));
111
- }
108
+ // To ensure that this shared_ptr instance is not deallocated before we are done
109
+ // running the update lambda we pass a shared from this to the lambda scope.
110
+ [weakSelf = weak_from_this()]() {
111
+ auto self = weakSelf.lock();
112
+ if(self) {
113
+ auto selfClockValue = std::dynamic_pointer_cast<RNSkClockValue>(self);
114
+ if(selfClockValue->getState() == RNSkClockState::Running) {
115
+ auto now = std::chrono::high_resolution_clock::now();
116
+ auto deltaFromStart = std::chrono::duration_cast<std::chrono::milliseconds>(now - selfClockValue->_start).count();
117
+ selfClockValue->tick(selfClockValue->_runtime, static_cast<double>(deltaFromStart));
118
+ }
119
+ }
112
120
  });
113
121
  }
114
122
 
@@ -127,7 +135,7 @@ protected:
127
135
  size_t _identifier;
128
136
  std::chrono::time_point<std::chrono::steady_clock> _start;
129
137
  std::chrono::time_point<std::chrono::steady_clock> _stop;
130
- std::atomic<RNSkClockState> _state;
138
+ std::atomic<RNSkClockState> _state = { RNSkClockState::NotStarted };
131
139
  };
132
140
 
133
141
  }
@@ -39,6 +39,11 @@ public:
39
39
  jsi::detail::throwJSError(runtime, "Expected array of dependencies as second parameter");
40
40
  }
41
41
 
42
+ // Get callback for calculating result
43
+ _callback = std::make_shared<jsi::Function>(arguments[0].asObject(runtime).asFunction(runtime));
44
+ }
45
+
46
+ void initializeDependencies(jsi::Runtime &runtime, const jsi::Value *arguments, size_t count) {
42
47
  // Save dependencies
43
48
  std::vector<std::shared_ptr<RNSkReadonlyValue>> dependencies;
44
49
 
@@ -59,21 +64,23 @@ public:
59
64
  dependencies.push_back(value);
60
65
  }
61
66
 
62
- // Get callback for calculating result
63
- _callback = std::make_shared<jsi::Function>(arguments[0].asObject(runtime).asFunction(runtime));
64
-
65
67
  // register change handler on dependencies
66
68
  _unsubscribers.reserve(_unsubscribers.size() + size);
67
69
  for(const auto &dep: dependencies) {
68
- auto dispatcher = std::bind(&RNSkDerivedValue::dependencyUpdated, this, std::placeholders::_1);
69
- _unsubscribers.push_back(dep->addListener(dispatcher));
70
+ _unsubscribers.push_back(dep->addListener([weakSelf = weak_from_this()](jsi::Runtime& runtime) {
71
+ auto self = weakSelf.lock();
72
+ if(self) {
73
+ auto selfAsThis = std::dynamic_pointer_cast<RNSkDerivedValue>(self);
74
+ selfAsThis->dependencyUpdated(runtime);
75
+ }
76
+ }));
70
77
  }
71
78
 
72
79
  // Set initial value
73
80
  dependencyUpdated(runtime);
74
81
  }
75
82
 
76
- ~RNSkDerivedValue() {
83
+ virtual ~RNSkDerivedValue() {
77
84
  // Unregister listeners
78
85
  for(const auto &unsubscribe: _unsubscribers) {
79
86
  unsubscribe();