@shopify/react-native-skia 0.1.178 → 0.1.181

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 (46) hide show
  1. package/android/build.gradle +6 -1
  2. package/cpp/jsi/RuntimeAwareCache.cpp +0 -2
  3. package/cpp/rnskia/RNSkDomView.cpp +2 -2
  4. package/cpp/rnskia/RNSkPlatformContext.h +2 -2
  5. package/cpp/rnskia/RNSkView.h +5 -3
  6. package/cpp/rnskia/dom/base/JsiDependencyManager.h +10 -6
  7. package/cpp/rnskia/dom/base/JsiDomNode.h +133 -78
  8. package/cpp/rnskia/dom/base/JsiDomRenderNode.h +8 -8
  9. package/cpp/rnskia/dom/base/NodeProp.h +5 -5
  10. package/cpp/rnskia/dom/base/NodePropsContainer.h +7 -1
  11. package/cpp/rnskia/dom/nodes/JsiImageFilterNodes.h +10 -9
  12. package/cpp/rnskia/dom/props/ClipProp.h +13 -20
  13. package/cpp/rnskia/dom/props/PathProp.h +16 -14
  14. package/cpp/rnskia/dom/props/PointProp.h +1 -1
  15. package/cpp/rnskia/dom/props/RRectProp.h +39 -61
  16. package/cpp/rnskia/dom/props/RectProp.h +27 -25
  17. package/ios/RNSkia-iOS/RNSkiOSPlatformContext.mm +0 -2
  18. package/lib/commonjs/dom/nodes/paint/ImageFilters.js +10 -2
  19. package/lib/commonjs/dom/nodes/paint/ImageFilters.js.map +1 -1
  20. package/lib/commonjs/external/reanimated/moduleWrapper.d.ts +2 -2
  21. package/lib/commonjs/external/reanimated/moduleWrapper.js +33 -37
  22. package/lib/commonjs/external/reanimated/moduleWrapper.js.map +1 -1
  23. package/lib/commonjs/external/reanimated/renderHelpers.js +2 -6
  24. package/lib/commonjs/external/reanimated/renderHelpers.js.map +1 -1
  25. package/lib/commonjs/external/reanimated/useSharedValueEffect.js +1 -1
  26. package/lib/commonjs/external/reanimated/useSharedValueEffect.js.map +1 -1
  27. package/lib/commonjs/views/SkiaBaseWebView.js +5 -1
  28. package/lib/commonjs/views/SkiaBaseWebView.js.map +1 -1
  29. package/lib/module/dom/nodes/paint/ImageFilters.js +10 -2
  30. package/lib/module/dom/nodes/paint/ImageFilters.js.map +1 -1
  31. package/lib/module/external/reanimated/moduleWrapper.d.ts +2 -2
  32. package/lib/module/external/reanimated/moduleWrapper.js +31 -32
  33. package/lib/module/external/reanimated/moduleWrapper.js.map +1 -1
  34. package/lib/module/external/reanimated/renderHelpers.js +3 -7
  35. package/lib/module/external/reanimated/renderHelpers.js.map +1 -1
  36. package/lib/module/external/reanimated/useSharedValueEffect.js +2 -2
  37. package/lib/module/external/reanimated/useSharedValueEffect.js.map +1 -1
  38. package/lib/module/views/SkiaBaseWebView.js +5 -1
  39. package/lib/module/views/SkiaBaseWebView.js.map +1 -1
  40. package/lib/typescript/src/external/reanimated/moduleWrapper.d.ts +2 -2
  41. package/package.json +1 -1
  42. package/src/dom/nodes/paint/ImageFilters.ts +8 -2
  43. package/src/external/reanimated/moduleWrapper.ts +36 -38
  44. package/src/external/reanimated/renderHelpers.ts +3 -7
  45. package/src/external/reanimated/useSharedValueEffect.ts +2 -2
  46. package/src/views/SkiaBaseWebView.tsx +5 -0
@@ -28,6 +28,11 @@ def safeExtGet(prop, fallback) {
28
28
 
29
29
  apply plugin: 'com.android.library'
30
30
 
31
+ def reactNativeArchitectures() {
32
+ def value = project.getProperties().get("reactNativeArchitectures")
33
+ return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
34
+ }
35
+
31
36
  static def findNodeModules(baseDir) {
32
37
  def basePath = baseDir.toPath().normalize()
33
38
  // Node's module resolution algorithm searches up to the root directory,
@@ -119,7 +124,7 @@ android {
119
124
  externalNativeBuild {
120
125
  cmake {
121
126
  cppFlags "-fexceptions", "-frtti", "-std=c++1y", "-DONANDROID"
122
- abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
127
+ abiFilters (*reactNativeArchitectures())
123
128
  arguments '-DANDROID_STL=c++_shared',
124
129
  "-DREACT_NATIVE_VERSION=${REACT_NATIVE_VERSION}",
125
130
  "-DNODE_MODULES_DIR=${nodeModules}",
@@ -1,5 +1,3 @@
1
- #pragma once
2
-
3
1
  #include "RuntimeAwareCache.h"
4
2
 
5
3
  namespace RNJsi {
@@ -22,7 +22,7 @@ RNSkDomRenderer::RNSkDomRenderer(std::function<void()> requestRedraw,
22
22
 
23
23
  RNSkDomRenderer::~RNSkDomRenderer() {
24
24
  if (_root != nullptr) {
25
- _root->dispose();
25
+ _root->dispose(true);
26
26
  _root = nullptr;
27
27
  }
28
28
  }
@@ -63,7 +63,7 @@ void RNSkDomRenderer::renderImmediate(
63
63
  void RNSkDomRenderer::setRoot(std::shared_ptr<JsiDomRenderNode> node) {
64
64
  std::lock_guard<std::mutex> lock(_rootLock);
65
65
  if (_root != nullptr) {
66
- _root->dispose();
66
+ _root->dispose(true);
67
67
  _root = nullptr;
68
68
  }
69
69
  _root = node;
@@ -112,8 +112,8 @@ public:
112
112
 
113
113
  /**
114
114
  * Creates an offscreen surface
115
- * @param width
116
- * @param height
115
+ * @param width width of the surface
116
+ * @param height height of the surface
117
117
  * @return sk_sp<SkSurface>
118
118
  */
119
119
  virtual sk_sp<SkSurface> makeOffscreenSurface(int width, int height) = 0;
@@ -88,10 +88,11 @@ protected:
88
88
 
89
89
  class RNSkImageCanvasProvider : public RNSkCanvasProvider {
90
90
  public:
91
- RNSkImageCanvasProvider(std::function<void()> requestRedraw, float width,
91
+ RNSkImageCanvasProvider(std::shared_ptr<RNSkPlatformContext> context,
92
+ std::function<void()> requestRedraw, float width,
92
93
  float height)
93
94
  : RNSkCanvasProvider(requestRedraw), _width(width), _height(height) {
94
- _surface = SkSurface::MakeRasterN32Premul(_width, _height);
95
+ _surface = context->makeOffscreenSurface(_width, _height);
95
96
  }
96
97
 
97
98
  /**
@@ -261,8 +262,9 @@ public:
261
262
  Renders the view into an SkImage instead of the screen.
262
263
  */
263
264
  sk_sp<SkImage> makeImageSnapshot(std::shared_ptr<SkRect> bounds) {
265
+
264
266
  auto provider = std::make_shared<RNSkImageCanvasProvider>(
265
- std::bind(&RNSkView::requestRedraw, this),
267
+ getPlatformContext(), std::bind(&RNSkView::requestRedraw, this),
266
268
  _canvasProvider->getScaledWidth(), _canvasProvider->getScaledHeight());
267
269
 
268
270
  _renderer->renderImmediate(provider);
@@ -23,8 +23,10 @@ class JsiDependencyManager
23
23
  public std::enable_shared_from_this<JsiDependencyManager> {
24
24
  public:
25
25
  JsiDependencyManager(std::shared_ptr<RNSkPlatformContext> context,
26
- jsi::Object &&registerValuesCallback)
27
- : _registerValuesCallback(std::move(registerValuesCallback)),
26
+ jsi::Runtime &runtime,
27
+ const jsi::Value &registerValuesCallback)
28
+ : _registerValuesCallback(std::make_shared<jsi::Object>(
29
+ registerValuesCallback.asObject(runtime))),
28
30
  JsiHostObject() {}
29
31
 
30
32
  ~JsiDependencyManager() { unsubscribeAll(); }
@@ -158,7 +160,7 @@ public:
158
160
  }
159
161
 
160
162
  // Call JS registerValues callback
161
- auto func = _registerValuesCallback.asFunction(runtime);
163
+ auto func = _registerValuesCallback->asFunction(runtime);
162
164
  _unregisterValues = std::make_shared<jsi::Object>(
163
165
  func.call(runtime, array, 1).asObject(runtime));
164
166
 
@@ -187,6 +189,8 @@ public:
187
189
 
188
190
  unsubscribeAll();
189
191
 
192
+ _registerValuesCallback = nullptr;
193
+
190
194
  return jsi::Value::undefined();
191
195
  }
192
196
 
@@ -203,8 +207,8 @@ public:
203
207
  return JSI_HOST_FUNCTION_LAMBDA {
204
208
  // Params: registerValues: (values: Array<SkiaValue<unknown>>) => () =>
205
209
  // void
206
- auto obj = std::make_shared<JsiDependencyManager>(
207
- context, getArgumentAsObject(runtime, arguments, count, 0));
210
+ auto obj = std::make_shared<JsiDependencyManager>(context, runtime,
211
+ arguments[0]);
208
212
 
209
213
  return jsi::Object::createFromHostObject(runtime, std::move(obj));
210
214
  };
@@ -283,7 +287,7 @@ private:
283
287
  return false;
284
288
  }
285
289
 
286
- jsi::Object _registerValuesCallback;
290
+ std::shared_ptr<jsi::Object> _registerValuesCallback;
287
291
  std::shared_ptr<jsi::Object> _unregisterValues;
288
292
  std::map<JsiDomNode *,
289
293
  std::vector<std::pair<std::shared_ptr<RNSkReadonlyValue>,
@@ -49,7 +49,19 @@ public:
49
49
  JsiDomNode(std::shared_ptr<RNSkPlatformContext> context, const char *type,
50
50
  NodeClass nodeClass)
51
51
  : _type(type), _context(context), _nodeClass(nodeClass),
52
- _nodeId(NodeIdent++), JsiHostObject() {}
52
+ _nodeId(NodeIdent++), JsiHostObject() {
53
+ #if SKIA_DOM_DEBUG
54
+ printDebugInfo("JsiDomNode." + std::string(_type) +
55
+ " CTOR - nodeId: " + std::to_string(_nodeId));
56
+ #endif
57
+ }
58
+
59
+ virtual ~JsiDomNode() {
60
+ #if SKIA_DOM_DEBUG
61
+ printDebugInfo("JsiDomNode." + std::string(_type) +
62
+ " DTOR - nodeId: " + std::to_string(_nodeId));
63
+ #endif
64
+ }
53
65
 
54
66
  /**
55
67
  Called when creating the node, resolves properties from the node constructor.
@@ -65,7 +77,7 @@ public:
65
77
  JSI_HOST_FUNCTION(setProps) {
66
78
  if (count == 1) {
67
79
  // Initialize properties container
68
- setProps(runtime, getArgumentAsObject(runtime, arguments, count, 0));
80
+ setProps(runtime, arguments[0]);
69
81
  } else {
70
82
  setEmptyProps();
71
83
  }
@@ -102,7 +114,7 @@ public:
102
114
  tree. Use for cleaning up.
103
115
  */
104
116
  JSI_HOST_FUNCTION(dispose) {
105
- dispose();
117
+ dispose(false);
106
118
  return jsi::Value::undefined();
107
119
  }
108
120
 
@@ -247,36 +259,9 @@ public:
247
259
  _propsContainer->markAsResolved();
248
260
  }
249
261
 
250
- // Now let's dispose if needed
262
+ // Now let's invalidate if needed
251
263
  if (_isDisposing && !_isDisposed) {
252
- _isDisposed = true;
253
-
254
- this->setParent(nullptr);
255
-
256
- // Callback signaling that we're done
257
- if (_disposeCallback != nullptr) {
258
- _disposeCallback();
259
- _disposeCallback = nullptr;
260
- }
261
-
262
- // Clear props
263
- if (_propsContainer != nullptr) {
264
- _propsContainer->dispose();
265
- }
266
-
267
- // Remove children
268
- std::vector<std::shared_ptr<JsiDomNode>> tmp;
269
- {
270
- std::lock_guard<std::mutex> lock(_childrenLock);
271
- tmp.reserve(_children.size());
272
- for (auto &child : _children) {
273
- tmp.push_back(child);
274
- }
275
- _children.clear();
276
- }
277
- for (auto &child : tmp) {
278
- child->dispose();
279
- }
264
+ invalidate();
280
265
  }
281
266
 
282
267
  // Resolve children
@@ -292,6 +277,22 @@ public:
292
277
  // Empty implementation
293
278
  }
294
279
 
280
+ /**
281
+ Called when a node has been removed from the dom tree and needs to be cleaned
282
+ up. If the invalidate parameter is set, we will invalidate the node directly.
283
+ Calling dispose from the JS dispose function calls this with invalidate set
284
+ to false, while the dom render view calls this with true.
285
+ */
286
+ virtual void dispose(bool immediate) {
287
+ if (_isDisposing) {
288
+ return;
289
+ }
290
+ _isDisposing = true;
291
+ if (immediate) {
292
+ invalidate();
293
+ }
294
+ }
295
+
295
296
  protected:
296
297
  /**
297
298
  Adds an operation that will be executed when the render cycle is finished.
@@ -319,24 +320,17 @@ protected:
319
320
 
320
321
  /**
321
322
  Native implementation of the set properties method. This is called from the
322
- reconciler when properties are set due to changes in React. This method will
323
- always call the onPropsSet method as a signal that things have changed.
323
+ reconciler when properties are set due to changes in React.
324
324
  */
325
- void setProps(jsi::Runtime &runtime, jsi::Object &&props) {
325
+ void setProps(jsi::Runtime &runtime, const jsi::Value &maybeProps) {
326
326
  #if SKIA_DOM_DEBUG
327
327
  printDebugInfo("JS:setProps(nodeId: " + std::to_string(_nodeId) + ")");
328
328
  #endif
329
- if (_propsContainer == nullptr) {
329
+ // Initialize properties container
330
+ ensurePropertyContainer();
330
331
 
331
- // Initialize properties container
332
- _propsContainer = std::make_shared<NodePropsContainer>(
333
- getType(), [=](BaseNodeProp *p) { onPropertyChanged(p); });
334
-
335
- // Ask sub classes to define their properties
336
- defineProperties(_propsContainer.get());
337
- }
338
332
  // Update properties container
339
- _propsContainer->setProps(runtime, std::move(props));
333
+ _propsContainer->setProps(runtime, maybeProps);
340
334
 
341
335
  // Invalidate context
342
336
  invalidateContext();
@@ -349,15 +343,8 @@ protected:
349
343
  #if SKIA_DOM_DEBUG
350
344
  printDebugInfo("JS:setEmptyProps(nodeId: " + std::to_string(_nodeId) + ")");
351
345
  #endif
352
- if (_propsContainer == nullptr) {
353
-
354
- // Initialize properties container
355
- _propsContainer = std::make_shared<NodePropsContainer>(
356
- getType(), [=](BaseNodeProp *p) { onPropertyChanged(p); });
357
-
358
- // Ask sub classes to define their properties
359
- defineProperties(_propsContainer.get());
360
- }
346
+ // Initialize properties container
347
+ ensurePropertyContainer();
361
348
  }
362
349
 
363
350
  /**
@@ -381,9 +368,12 @@ protected:
381
368
  printDebugInfo("JS:addChild(childId: " + std::to_string(child->_nodeId) +
382
369
  ")");
383
370
  #endif
384
- enqueAsynOperation([child, this]() {
385
- _children.push_back(child);
386
- child->setParent(this);
371
+ enqueAsynOperation([child, weakSelf = weak_from_this()]() {
372
+ auto self = weakSelf.lock();
373
+ if (self) {
374
+ self->_children.push_back(child);
375
+ child->setParent(self.get());
376
+ }
387
377
  });
388
378
  }
389
379
 
@@ -398,10 +388,14 @@ protected:
398
388
  "JS:insertChildBefore(childId: " + std::to_string(child->_nodeId) +
399
389
  ", beforeId: " + std::to_string(before->_nodeId) + ")");
400
390
  #endif
401
- enqueAsynOperation([child, before, this]() {
402
- auto position = std::find(_children.begin(), _children.end(), before);
403
- _children.insert(position, child);
404
- child->setParent(this);
391
+ enqueAsynOperation([child, before, weakSelf = weak_from_this()]() {
392
+ auto self = weakSelf.lock();
393
+ if (self) {
394
+ auto position =
395
+ std::find(self->_children.begin(), self->_children.end(), before);
396
+ self->_children.insert(position, child);
397
+ child->setParent(self.get());
398
+ }
405
399
  });
406
400
  }
407
401
 
@@ -414,27 +408,25 @@ protected:
414
408
  printDebugInfo("JS:removeChild(childId: " + std::to_string(child->_nodeId) +
415
409
  ")");
416
410
  #endif
417
- enqueAsynOperation([child, this]() {
418
- // Delete child itself
419
- _children.erase(
420
- std::remove_if(_children.begin(), _children.end(),
421
- [child](const auto &node) { return node == child; }),
422
- _children.end());
423
-
424
- child->dispose();
425
- });
426
- }
411
+ auto removeChild = [child,
412
+ weakSelf = weak_from_this()](bool immediate = false) {
413
+ auto self = weakSelf.lock();
414
+ if (self) {
415
+ // Delete child itself
416
+ self->_children.erase(
417
+ std::remove_if(self->_children.begin(), self->_children.end(),
418
+ [child](const auto &node) { return node == child; }),
419
+ self->_children.end());
420
+
421
+ child->dispose(immediate);
422
+ }
423
+ };
427
424
 
428
- /**
429
- Called when a node has been removed from the dom tree and needs to be cleaned
430
- up.
431
- */
432
- virtual void dispose() {
433
425
  if (_isDisposing) {
434
- return;
426
+ removeChild(false);
427
+ } else {
428
+ enqueAsynOperation(removeChild);
435
429
  }
436
-
437
- _isDisposing = true;
438
430
  }
439
431
 
440
432
  #if SKIA_DOM_DEBUG
@@ -477,6 +469,69 @@ protected:
477
469
  }
478
470
 
479
471
  private:
472
+ /**
473
+ Invalidates the node - meaning removing and clearing children and properties
474
+ **/
475
+ void invalidate() {
476
+ if (_isDisposing && !_isDisposed) {
477
+ #if SKIA_DOM_DEBUG
478
+ printDebugInfo("JsiDomNode::invalidate: nodeid: " +
479
+ std::to_string(_nodeId));
480
+ #endif
481
+
482
+ _isDisposed = true;
483
+
484
+ // Clear parent
485
+ this->setParent(nullptr);
486
+
487
+ // Clear any async operations
488
+ _queuedNodeOps.clear();
489
+
490
+ // Callback signaling that we're done
491
+ if (_disposeCallback != nullptr) {
492
+ _disposeCallback();
493
+ _disposeCallback = nullptr;
494
+ }
495
+
496
+ // Clear props
497
+ if (_propsContainer != nullptr) {
498
+ _propsContainer->dispose();
499
+ }
500
+
501
+ // Remove children
502
+ std::vector<std::shared_ptr<JsiDomNode>> tmp;
503
+ {
504
+ std::lock_guard<std::mutex> lock(_childrenLock);
505
+ tmp.reserve(_children.size());
506
+ for (auto &child : _children) {
507
+ tmp.push_back(child);
508
+ }
509
+ _children.clear();
510
+ }
511
+ for (auto &child : tmp) {
512
+ child->dispose(true);
513
+ }
514
+ }
515
+ }
516
+
517
+ /**
518
+ Creates and sets up the property container
519
+ */
520
+ void ensurePropertyContainer() {
521
+ if (_propsContainer == nullptr) {
522
+ _propsContainer = std::make_shared<NodePropsContainer>(
523
+ getType(), [weakSelf = weak_from_this()](BaseNodeProp *p) {
524
+ auto self = weakSelf.lock();
525
+ if (self) {
526
+ self->onPropertyChanged(p);
527
+ }
528
+ });
529
+
530
+ // Ask sub classes to define their properties
531
+ defineProperties(_propsContainer.get());
532
+ }
533
+ }
534
+
480
535
  const char *_type;
481
536
  std::shared_ptr<RNSkPlatformContext> _context;
482
537
 
@@ -132,19 +132,19 @@ public:
132
132
  */
133
133
  void resetPendingChanges() override { JsiDomNode::resetPendingChanges(); }
134
134
 
135
- /**
136
- Signal from the JS side that the node is removed from the dom.
137
- */
138
- void dispose() override { JsiDomNode::dispose(); }
139
-
140
135
  protected:
141
136
  /**
142
137
  Invalidates and marks then context as changed.
143
138
  */
144
139
  void invalidateContext() override {
145
- enqueAsynOperation([=]() {
146
- _paintCache.parent = nullptr;
147
- _paintCache.child = nullptr;
140
+ enqueAsynOperation([weakSelf = weak_from_this()]() {
141
+ auto self = weakSelf.lock();
142
+ if (self) {
143
+ std::static_pointer_cast<JsiDomRenderNode>(self)->_paintCache.parent =
144
+ nullptr;
145
+ std::static_pointer_cast<JsiDomRenderNode>(self)->_paintCache.child =
146
+ nullptr;
147
+ }
148
148
  });
149
149
  }
150
150
 
@@ -33,7 +33,7 @@ public:
33
33
  // readValueFromJS Function (which comes from the reconciler
34
34
  // setting a new property value on the property
35
35
  if (_value == nullptr) {
36
- _value = std::make_shared<JsiValue>(runtime, read(runtime, _name, this));
36
+ _value = std::make_unique<JsiValue>(runtime, read(runtime, _name, this));
37
37
  _isChanged = true;
38
38
  _hasNewValue = false;
39
39
  } else {
@@ -41,7 +41,7 @@ public:
41
41
  std::lock_guard<std::mutex> lock(_swapMutex);
42
42
  if (_buffer == nullptr) {
43
43
  _buffer =
44
- std::make_shared<JsiValue>(runtime, read(runtime, _name, this));
44
+ std::make_unique<JsiValue>(runtime, read(runtime, _name, this));
45
45
  } else {
46
46
  _buffer->setCurrent(runtime, read(runtime, _name, this));
47
47
  }
@@ -60,7 +60,7 @@ public:
60
60
  // and we don't want to rip out the underlying value object.
61
61
  std::lock_guard<std::mutex> lock(_swapMutex);
62
62
  if (_buffer == nullptr) {
63
- _buffer = std::make_shared<JsiValue>(runtime, value);
63
+ _buffer = std::make_unique<JsiValue>(runtime, value);
64
64
  } else {
65
65
  _buffer->setCurrent(runtime, value);
66
66
  }
@@ -129,8 +129,8 @@ private:
129
129
 
130
130
  std::function<void(BaseNodeProp *)> _onChange;
131
131
 
132
- std::shared_ptr<JsiValue> _value;
133
- std::shared_ptr<JsiValue> _buffer;
132
+ std::unique_ptr<JsiValue> _value;
133
+ std::unique_ptr<JsiValue> _buffer;
134
134
  std::atomic<bool> _isChanged = {false};
135
135
  std::atomic<bool> _hasNewValue = {false};
136
136
  std::mutex _swapMutex;
@@ -82,10 +82,16 @@ public:
82
82
  /**
83
83
  Called when the React / JS side sets properties on a node
84
84
  */
85
- void setProps(jsi::Runtime &runtime, jsi::Object &&props) {
85
+ void setProps(jsi::Runtime &runtime, const jsi::Value &maybePropsObject) {
86
86
  // Clear property mapping
87
87
  _mappedProperties.clear();
88
88
 
89
+ if (!maybePropsObject.isObject()) {
90
+ throw jsi::JSError(runtime, "Expected property object.");
91
+ }
92
+
93
+ auto props = maybePropsObject.asObject(runtime);
94
+
89
95
  // Use specialized reader function to be able to intercept calls that
90
96
  // reads specific named values from the js property object.
91
97
  auto read = [&](jsi::Runtime &runtime, PropId name, NodeProp *prop) {
@@ -158,20 +158,21 @@ public:
158
158
  : JsiBaseImageFilterNode(context, "skDisplacementMapImageFilter") {}
159
159
 
160
160
  void decorate(DeclarationContext *context) override {
161
-
161
+ decorateChildren(context);
162
162
  auto channelX =
163
163
  getColorChannelFromStringValue(_channelXProp->value().getAsString());
164
164
  auto channelY =
165
165
  getColorChannelFromStringValue(_channelYProp->value().getAsString());
166
166
  auto scale = _scaleProp->value().getAsNumber();
167
-
168
- auto displacement = context->getImageFilters()->pop();
169
-
170
- auto color = context->getImageFilters()->pop();
171
-
172
- composeAndPush(context, SkImageFilters::DisplacementMap(
173
- channelX, channelY, scale, displacement,
174
- color ? color : nullptr));
167
+ auto shader = context->getShaders()->pop();
168
+ if (!shader) {
169
+ throw std::runtime_error("DisplacementMap expects a shader as child");
170
+ }
171
+ auto map = SkImageFilters::Shader(shader);
172
+ auto input = context->getImageFilters()->pop();
173
+ auto imgf = SkImageFilters::DisplacementMap(channelX, channelY, scale, map,
174
+ input ? input : nullptr);
175
+ context->getImageFilters()->push(imgf);
175
176
  }
176
177
 
177
178
  protected:
@@ -22,43 +22,36 @@ public:
22
22
  explicit ClipProp(PropId name,
23
23
  const std::function<void(BaseNodeProp *)> &onChange)
24
24
  : BaseDerivedProp(onChange) {
25
- _pathProp = defineProperty<PathProp>(name);
26
- _rectProp = defineProperty<RectProp>(name);
27
- _rrectProp = defineProperty<RRectProp>(name);
25
+ _clipProp = defineProperty<NodeProp>(name);
28
26
  }
29
27
 
30
28
  void updateDerivedValue() override {
31
- if (_pathProp->isSet()) {
32
- _rect = nullptr;
33
- _rrect = nullptr;
34
- _path = _pathProp->getDerivedValue();
35
- } else if (_rrectProp->isSet()) {
36
- _rect = nullptr;
37
- _rrect = _rrectProp->getDerivedValue();
38
- _path = nullptr;
39
- } else if (_rectProp->isSet()) {
40
- _rect = _rectProp->getDerivedValue();
29
+ if (_clipProp->isSet()) {
30
+ auto value = _clipProp->value();
31
+ _rect = RectProp::processRect(value);
41
32
  _rrect = nullptr;
42
33
  _path = nullptr;
34
+ if (!_rect) {
35
+ _path = PathProp::processPath(value);
36
+ if (!_path) {
37
+ _rrect = RRectProp::processRRect(value);
38
+ }
39
+ }
43
40
  }
44
41
  }
45
42
 
46
- bool isSet() override {
47
- return _pathProp->isSet() || _rectProp->isSet() || _rrectProp->isSet();
48
- }
43
+ bool isSet() override { return _clipProp->isSet(); }
49
44
 
50
45
  const SkPath *getPath() { return _path.get(); }
51
46
  const SkRect *getRect() { return _rect.get(); }
52
47
  const SkRRect *getRRect() { return _rrect.get(); }
53
48
 
54
49
  private:
55
- PathProp *_pathProp;
56
- RectProp *_rectProp;
57
- RRectProp *_rrectProp;
50
+ NodeProp *_clipProp;
58
51
 
59
52
  std::shared_ptr<const SkPath> _path;
60
53
  std::shared_ptr<const SkRect> _rect;
61
54
  std::shared_ptr<const SkRRect> _rrect;
62
55
  };
63
56
 
64
- } // namespace RNSkia
57
+ } // namespace RNSkia
@@ -22,32 +22,34 @@ public:
22
22
  _pathProp = defineProperty<NodeProp>(name);
23
23
  }
24
24
 
25
- void updateDerivedValue() override {
26
- if (!_pathProp->isSet()) {
27
- setDerivedValue(nullptr);
28
- return;
29
- }
30
-
31
- if (_pathProp->value().getType() == PropType::HostObject) {
25
+ static std::shared_ptr<SkPath> processPath(const JsiValue &value) {
26
+ if (value.getType() == PropType::HostObject) {
32
27
  // Try reading as Path
33
- auto ptr = std::dynamic_pointer_cast<JsiSkPath>(
34
- _pathProp->value().getAsHostObject());
28
+ auto ptr = std::dynamic_pointer_cast<JsiSkPath>(value.getAsHostObject());
35
29
  if (ptr != nullptr) {
36
- setDerivedValue(ptr->getObject());
30
+ return ptr->getObject();
37
31
  }
38
- } else if (_pathProp->value().getType() == PropType::String) {
32
+ } else if (value.getType() == PropType::String) {
39
33
  // Read as string
40
- auto pathString = _pathProp->value().getAsString();
34
+ auto pathString = value.getAsString();
41
35
  SkPath result;
42
36
 
43
37
  if (SkParsePath::FromSVGString(pathString.c_str(), &result)) {
44
- setDerivedValue(std::make_shared<SkPath>(result));
38
+ return std::make_shared<SkPath>(result);
45
39
  } else {
46
40
  throw std::runtime_error("Could not parse path from string.");
47
41
  }
48
- } else {
42
+ }
43
+ return nullptr;
44
+ }
45
+
46
+ void updateDerivedValue() override {
47
+ if (!_pathProp->isSet()) {
49
48
  setDerivedValue(nullptr);
49
+ return;
50
50
  }
51
+ auto value = _pathProp->value();
52
+ setDerivedValue(PathProp::processPath(value));
51
53
  }
52
54
 
53
55
  private:
@@ -29,7 +29,7 @@ public:
29
29
  void updateDerivedValue() override {
30
30
  if (_pointProp->isSet()) {
31
31
  // Check for JsiSkRect and JsiSkPoint
32
- setDerivedValue(std::move(processValue(_pointProp->value())));
32
+ setDerivedValue(processValue(_pointProp->value()));
33
33
  } else {
34
34
  setDerivedValue(nullptr);
35
35
  }