@shopify/react-native-skia 0.1.120 → 0.1.123

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. package/android/CMakeLists.txt +33 -17
  2. package/android/build.gradle +81 -34
  3. package/android/cpp/jni/JniSkiaDrawView.cpp +14 -71
  4. package/android/cpp/jni/JniSkiaManager.cpp +1 -1
  5. package/android/cpp/jni/include/JniSkiaDrawView.h +18 -22
  6. package/android/cpp/jni/include/JniSkiaManager.h +4 -4
  7. package/android/cpp/rnskia-android/RNSkDrawViewImpl.cpp +68 -0
  8. package/android/cpp/rnskia-android/RNSkDrawViewImpl.h +48 -0
  9. package/android/cpp/{jni/include/JniPlatformContextWrapper.h → rnskia-android/RNSkPlatformContextImpl.h} +4 -4
  10. package/android/cpp/{jni → rnskia-android}/SkiaOpenGLRenderer.cpp +39 -54
  11. package/android/cpp/{jni/include → rnskia-android}/SkiaOpenGLRenderer.h +2 -31
  12. package/android/src/main/java/com/shopify/reactnative/skia/PlatformContext.java +1 -1
  13. package/android/src/main/java/com/shopify/reactnative/skia/RNSkiaViewManager.java +1 -1
  14. package/android/src/main/java/com/shopify/reactnative/skia/SkiaDrawView.java +21 -28
  15. package/cpp/api/JsiSkApi.h +2 -0
  16. package/cpp/api/JsiSkColor.h +49 -0
  17. package/cpp/api/JsiSkPath.h +31 -2
  18. package/cpp/api/JsiSkPathFactory.h +96 -1
  19. package/cpp/api/third_party/CSSColorParser.h +324 -0
  20. package/cpp/rnskia/RNSkAnimation.h +4 -7
  21. package/cpp/rnskia/RNSkDrawView.cpp +77 -116
  22. package/cpp/rnskia/RNSkDrawView.h +5 -35
  23. package/cpp/rnskia/RNSkJsiViewApi.h +8 -5
  24. package/cpp/rnskia/RNSkManager.cpp +2 -2
  25. package/cpp/rnskia/RNSkManager.h +2 -2
  26. package/cpp/rnskia/RNSkPlatformContext.h +1 -1
  27. package/cpp/rnskia/values/RNSkClockValue.h +19 -11
  28. package/cpp/rnskia/values/RNSkDerivedValue.h +1 -1
  29. package/cpp/rnskia/values/RNSkReadonlyValue.h +15 -15
  30. package/cpp/utils/RNSkTimingInfo.h +13 -1
  31. package/ios/RNSkia-iOS/RNSkDrawViewImpl.h +5 -7
  32. package/ios/RNSkia-iOS/RNSkDrawViewImpl.mm +25 -10
  33. package/ios/RNSkia-iOS/SkiaDrawView.mm +21 -15
  34. package/lib/commonjs/renderer/Canvas.js +3 -3
  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/shapes/Path.js +10 -2
  39. package/lib/commonjs/renderer/components/shapes/Path.js.map +1 -1
  40. package/lib/commonjs/renderer/nodes/Node.js +3 -3
  41. package/lib/commonjs/renderer/nodes/Node.js.map +1 -1
  42. package/lib/commonjs/renderer/processors/Paint.js +6 -1
  43. package/lib/commonjs/renderer/processors/Paint.js.map +1 -1
  44. package/lib/commonjs/skia/Color.js +3 -25
  45. package/lib/commonjs/skia/Color.js.map +1 -1
  46. package/lib/commonjs/skia/Image/Image.js.map +1 -1
  47. package/lib/commonjs/skia/ImageFilter/ImageFilterFactory.js.map +1 -1
  48. package/lib/commonjs/skia/Paint/Paint.js +13 -1
  49. package/lib/commonjs/skia/Paint/Paint.js.map +1 -1
  50. package/lib/commonjs/skia/Paint/usePaint.js +2 -4
  51. package/lib/commonjs/skia/Paint/usePaint.js.map +1 -1
  52. package/lib/commonjs/skia/Path/Path.js +13 -1
  53. package/lib/commonjs/skia/Path/Path.js.map +1 -1
  54. package/lib/commonjs/skia/Shader/Shader.js.map +1 -1
  55. package/lib/commonjs/skia/Skia.js +43 -3
  56. package/lib/commonjs/skia/Skia.js.map +1 -1
  57. package/lib/module/renderer/Canvas.js +2 -2
  58. package/lib/module/renderer/Canvas.js.map +1 -1
  59. package/lib/module/renderer/components/Paint.js +2 -2
  60. package/lib/module/renderer/components/Paint.js.map +1 -1
  61. package/lib/module/renderer/components/shapes/Path.js +10 -3
  62. package/lib/module/renderer/components/shapes/Path.js.map +1 -1
  63. package/lib/module/renderer/nodes/Node.js +3 -3
  64. package/lib/module/renderer/nodes/Node.js.map +1 -1
  65. package/lib/module/renderer/processors/Paint.js +6 -1
  66. package/lib/module/renderer/processors/Paint.js.map +1 -1
  67. package/lib/module/skia/Color.js +2 -21
  68. package/lib/module/skia/Color.js.map +1 -1
  69. package/lib/module/skia/Image/Image.js.map +1 -1
  70. package/lib/module/skia/ImageFilter/ImageFilterFactory.js.map +1 -1
  71. package/lib/module/skia/Paint/Paint.js +6 -0
  72. package/lib/module/skia/Paint/Paint.js.map +1 -1
  73. package/lib/module/skia/Paint/usePaint.js +2 -3
  74. package/lib/module/skia/Paint/usePaint.js.map +1 -1
  75. package/lib/module/skia/Path/Path.js +11 -0
  76. package/lib/module/skia/Path/Path.js.map +1 -1
  77. package/lib/module/skia/Shader/Shader.js.map +1 -1
  78. package/lib/module/skia/Skia.js +45 -2
  79. package/lib/module/skia/Skia.js.map +1 -1
  80. package/lib/typescript/src/renderer/components/shapes/Path.d.ts +3 -1
  81. package/lib/typescript/src/renderer/processors/Paint.d.ts +2 -1
  82. package/lib/typescript/src/skia/Color.d.ts +0 -1
  83. package/lib/typescript/src/skia/Image/Image.d.ts +3 -3
  84. package/lib/typescript/src/skia/ImageFilter/ImageFilterFactory.d.ts +2 -2
  85. package/lib/typescript/src/skia/Paint/Paint.d.ts +3 -2
  86. package/lib/typescript/src/skia/Path/Path.d.ts +13 -0
  87. package/lib/typescript/src/skia/Path/PathFactory.d.ts +7 -1
  88. package/lib/typescript/src/skia/Picture/Picture.d.ts +2 -2
  89. package/lib/typescript/src/skia/RuntimeEffect/RuntimeEffect.d.ts +3 -3
  90. package/lib/typescript/src/skia/Shader/Shader.d.ts +2 -2
  91. package/lib/typescript/src/skia/Shader/ShaderFactory.d.ts +9 -9
  92. package/lib/typescript/src/skia/Skia.d.ts +5 -3
  93. package/package.json +1 -1
  94. package/scripts/install-npm.js +1 -1
  95. package/src/renderer/Canvas.tsx +2 -2
  96. package/src/renderer/components/Paint.tsx +2 -2
  97. package/src/renderer/components/shapes/Path.tsx +12 -4
  98. package/src/renderer/nodes/Node.ts +3 -3
  99. package/src/renderer/processors/Paint.ts +5 -0
  100. package/src/skia/Color.ts +3 -20
  101. package/src/skia/Image/Image.ts +3 -3
  102. package/src/skia/ImageFilter/ImageFilterFactory.ts +2 -2
  103. package/src/skia/Paint/Paint.ts +9 -2
  104. package/src/skia/Paint/usePaint.ts +2 -4
  105. package/src/skia/Path/Path.ts +16 -0
  106. package/src/skia/Path/PathFactory.ts +8 -1
  107. package/src/skia/Picture/Picture.ts +2 -2
  108. package/src/skia/RuntimeEffect/RuntimeEffect.ts +4 -4
  109. package/src/skia/Shader/Shader.ts +2 -2
  110. package/src/skia/Shader/ShaderFactory.ts +9 -9
  111. package/src/skia/Skia.ts +47 -3
@@ -1,9 +1,9 @@
1
1
  #include "SkiaOpenGLRenderer.h"
2
2
 
3
3
  #include <RNSkLog.h>
4
+
4
5
  namespace RNSkia
5
6
  {
6
-
7
7
  /** Static members */
8
8
  std::shared_ptr<DrawingContext> SkiaOpenGLRenderer::getThreadDrawingContext()
9
9
  {
@@ -20,6 +20,11 @@ namespace RNSkia
20
20
  return threadContexts.at(threadId);
21
21
  }
22
22
 
23
+ SkiaOpenGLRenderer::SkiaOpenGLRenderer(ANativeWindow *surface, size_t renderId):
24
+ _surfaceTexture(surface),
25
+ _renderId(renderId) {
26
+ }
27
+
23
28
  void SkiaOpenGLRenderer::run(const sk_sp<SkPicture> picture, int width, int height)
24
29
  {
25
30
  switch (_renderState)
@@ -73,7 +78,16 @@ namespace RNSkia
73
78
  }
74
79
  case RenderState::Finishing:
75
80
  {
76
- finish();
81
+ _renderState = RenderState::Done;
82
+
83
+ if (_glSurface != EGL_NO_SURFACE && getThreadDrawingContext()->glDisplay != EGL_NO_DISPLAY)
84
+ {
85
+ eglDestroySurface(getThreadDrawingContext()->glDisplay, _glSurface);
86
+ }
87
+
88
+ _skSurface = nullptr;
89
+ _surfaceTexture = nullptr;
90
+
77
91
  break;
78
92
  }
79
93
  case RenderState::Done:
@@ -107,58 +121,11 @@ namespace RNSkia
107
121
  return true;
108
122
  }
109
123
 
110
- void SkiaOpenGLRenderer::finish()
111
- {
112
- std::lock_guard<std::mutex> lock(_lock);
113
-
114
- if (_renderState != RenderState::Finishing)
115
- {
116
- _cv.notify_all();
117
- return;
118
- }
119
-
120
- finishGL();
121
- finishSkiaSurface();
122
-
123
- _renderState = RenderState::Done;
124
-
125
- _cv.notify_one();
126
- }
127
-
128
- void SkiaOpenGLRenderer::finishGL()
129
- {
130
- if (_glSurface != EGL_NO_SURFACE && getThreadDrawingContext()->glDisplay != EGL_NO_DISPLAY)
131
- {
132
- eglDestroySurface(getThreadDrawingContext()->glDisplay, _glSurface);
133
- }
134
- }
135
-
136
- void SkiaOpenGLRenderer::finishSkiaSurface()
137
- {
138
- if (_skSurface != nullptr)
139
- {
140
- _skSurface = nullptr;
141
- }
142
-
143
- if (_nativeWindow != nullptr)
144
- {
145
- ANativeWindow_release(_nativeWindow);
146
- _nativeWindow = nullptr;
147
- }
148
- }
149
-
150
124
  void SkiaOpenGLRenderer::teardown()
151
125
  {
152
126
  _renderState = RenderState::Finishing;
153
127
  }
154
128
 
155
- void SkiaOpenGLRenderer::waitForTeardown()
156
- {
157
- std::unique_lock<std::mutex> lock(_lock);
158
- _cv.wait(lock, [this]
159
- { return (_renderState == RenderState::Done); });
160
- }
161
-
162
129
  bool SkiaOpenGLRenderer::initStaticGLContext()
163
130
  {
164
131
  if (getThreadDrawingContext()->glContext != EGL_NO_CONTEXT)
@@ -212,7 +179,12 @@ namespace RNSkia
212
179
 
213
180
  EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
214
181
 
215
- getThreadDrawingContext()->glContext = eglCreateContext(getThreadDrawingContext()->glDisplay, getThreadDrawingContext()->glConfig, NULL, contextAttribs);
182
+ getThreadDrawingContext()->glContext = eglCreateContext(
183
+ getThreadDrawingContext()->glDisplay,
184
+ getThreadDrawingContext()->glConfig,
185
+ NULL,
186
+ contextAttribs);
187
+
216
188
  if (getThreadDrawingContext()->glContext == EGL_NO_CONTEXT)
217
189
  {
218
190
  RNSkLogger::logToConsole(
@@ -244,14 +216,18 @@ namespace RNSkia
244
216
 
245
217
  bool SkiaOpenGLRenderer::initGLSurface()
246
218
  {
247
- if (_nativeWindow == nullptr)
219
+ if (_surfaceTexture == nullptr)
248
220
  {
249
221
  return false;
250
222
  }
251
223
 
252
224
  if (_glSurface != EGL_NO_SURFACE)
253
225
  {
254
- if (!eglMakeCurrent(getThreadDrawingContext()->glDisplay, _glSurface, _glSurface, getThreadDrawingContext()->glContext))
226
+ if (!eglMakeCurrent(
227
+ getThreadDrawingContext()->glDisplay,
228
+ _glSurface,
229
+ _glSurface,
230
+ getThreadDrawingContext()->glContext))
255
231
  {
256
232
  RNSkLogger::logToConsole(
257
233
  "eglMakeCurrent failed: %d\n", eglGetError());
@@ -262,7 +238,12 @@ namespace RNSkia
262
238
 
263
239
  // Create the opengl surface
264
240
  _glSurface =
265
- eglCreateWindowSurface(getThreadDrawingContext()->glDisplay, getThreadDrawingContext()->glConfig, _nativeWindow, nullptr);
241
+ eglCreateWindowSurface(
242
+ getThreadDrawingContext()->glDisplay,
243
+ getThreadDrawingContext()->glConfig,
244
+ _surfaceTexture,
245
+ nullptr);
246
+
266
247
  if (_glSurface == EGL_NO_SURFACE)
267
248
  {
268
249
  RNSkLogger::logToConsole(
@@ -270,7 +251,11 @@ namespace RNSkia
270
251
  return false;
271
252
  }
272
253
 
273
- if (!eglMakeCurrent(getThreadDrawingContext()->glDisplay, _glSurface, _glSurface, getThreadDrawingContext()->glContext))
254
+ if (!eglMakeCurrent(
255
+ getThreadDrawingContext()->glDisplay,
256
+ _glSurface,
257
+ _glSurface,
258
+ getThreadDrawingContext()->glContext))
274
259
  {
275
260
  RNSkLogger::logToConsole("eglMakeCurrent failed: %d\n", eglGetError());
276
261
  return false;
@@ -7,7 +7,6 @@
7
7
  #include "GLES2/gl2.h"
8
8
 
9
9
  #include <condition_variable>
10
- #include <mutex>
11
10
  #include <thread>
12
11
  #include <unordered_map>
13
12
 
@@ -45,9 +44,7 @@ namespace RNSkia
45
44
  class SkiaOpenGLRenderer
46
45
  {
47
46
  public:
48
- SkiaOpenGLRenderer(ANativeWindow *nativeWindow, size_t renderId) :
49
- _nativeWindow(nativeWindow),
50
- _renderId(renderId) { }
47
+ SkiaOpenGLRenderer(ANativeWindow *surface, size_t renderId);
51
48
 
52
49
  /**
53
50
  * Initializes, renders and tears down the render pipeline depending on the state of the
@@ -71,14 +68,6 @@ namespace RNSkia
71
68
  */
72
69
  void teardown();
73
70
 
74
- /**
75
- * Wait for teardown to finish. This means that we'll wait until the next
76
- * render which will handle releasing all OpenGL and Skia resources used for
77
- * this renderer. After tearing down the render will do nothing if the render
78
- * method is called again.
79
- */
80
- void waitForTeardown();
81
-
82
71
  private:
83
72
  /**
84
73
  * Initializes all required OpenGL and Skia objects
@@ -117,21 +106,6 @@ namespace RNSkia
117
106
  */
118
107
  bool ensureSkiaSurface(int width, int height);
119
108
 
120
- /**
121
- * Finalizes and releases all resources used by this renderer
122
- */
123
- void finish();
124
-
125
- /**
126
- * Destroys the underlying OpenGL surface used for this renderer
127
- */
128
- void finishGL();
129
-
130
- /**
131
- * Destroys the underlying Skia surface used for this renderer
132
- */
133
- void finishSkiaSurface();
134
-
135
109
  /**
136
110
  * To be able to use static contexts (and avoid reloading the skia context for each
137
111
  * new view, we track the OpenGL and Skia drawing context per thread.
@@ -141,7 +115,7 @@ namespace RNSkia
141
115
 
142
116
  EGLSurface _glSurface = EGL_NO_SURFACE;
143
117
 
144
- ANativeWindow *_nativeWindow = nullptr;
118
+ ANativeWindow *_surfaceTexture = nullptr;
145
119
  GrBackendRenderTarget _skRenderTarget;
146
120
  sk_sp<SkSurface> _skSurface;
147
121
 
@@ -150,9 +124,6 @@ namespace RNSkia
150
124
 
151
125
  size_t _renderId;
152
126
 
153
- std::mutex _lock;
154
- std::condition_variable _cv;
155
-
156
127
  std::atomic<RenderState> _renderState = { RenderState::Initializing };
157
128
  };
158
129
 
@@ -66,7 +66,7 @@ public class PlatformContext {
66
66
  Choreographer.getInstance().postFrameCallback(frameCallback);
67
67
  }
68
68
 
69
- public void raise(String message) {
69
+ public void raise(final String message) {
70
70
  new Handler(Looper.getMainLooper()).post(new Runnable() {
71
71
  @Override
72
72
  public void run() {
@@ -61,7 +61,7 @@ public class RNSkiaViewManager extends BaseViewManager<SkiaDrawView, LayoutShado
61
61
  Integer nativeId = mViewMapping.get(view);
62
62
  skiaModule.getSkiaManager().unregister(nativeId);
63
63
  mViewMapping.remove(view);
64
- view.onRemoved();
64
+ view.onViewRemoved();
65
65
  }
66
66
 
67
67
  @NonNull
@@ -18,10 +18,11 @@ public class SkiaDrawView extends TextureView implements TextureView.SurfaceText
18
18
  @DoNotStrip
19
19
  private HybridData mHybridData;
20
20
 
21
- private Surface mSurface;
21
+ @DoNotStrip
22
+ private boolean mViewRemoved;
22
23
 
23
24
  @DoNotStrip
24
- private boolean mIsRemoved = false;
25
+ private Surface mSurface;
25
26
 
26
27
  public SkiaDrawView(Context ctx) {
27
28
  super(ctx);
@@ -36,26 +37,25 @@ public class SkiaDrawView extends TextureView implements TextureView.SurfaceText
36
37
  // Texture view does not support setting the background color.
37
38
  }
38
39
 
39
- @Override
40
- protected void finalize() throws Throwable {
41
- mHybridData.resetNative();
42
- super.finalize();
40
+ public void releaseSurface() {
41
+ if(mSurface != null) {
42
+ mSurface.release();
43
+ mSurface = null;
44
+ }
45
+ // We can only reset the native side when the view was removed from screen.
46
+ // releasing the surface can also be done when the view is hidden and then
47
+ // we should only release the surface - and keep the native part around.
48
+ if(mViewRemoved) {
49
+ mHybridData.resetNative();
50
+ }
43
51
  }
44
52
 
45
-
46
- public void onRemoved() {
47
- // We'll mark the view removed since we reset the native part.
48
- // This means that none of the native methods should be called after
49
- // this point.
50
- mIsRemoved = true;
51
- mHybridData.resetNative();
53
+ void onViewRemoved() {
54
+ mViewRemoved = true;
52
55
  }
53
56
 
54
57
  @Override
55
58
  public boolean onTouchEvent(MotionEvent ev) {
56
- if(mIsRemoved) {
57
- return false;
58
- }
59
59
  int action = ev.getAction();
60
60
  int count = ev.getPointerCount();
61
61
  MotionEvent.PointerCoords r = new MotionEvent.PointerCoords();
@@ -88,30 +88,23 @@ public class SkiaDrawView extends TextureView implements TextureView.SurfaceText
88
88
 
89
89
  @Override
90
90
  public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
91
- if(mIsRemoved) {
92
- return;
93
- }
94
91
  mSurface = new Surface(surface);
95
92
  surfaceAvailable(mSurface, width, height);
96
93
  }
97
94
 
98
95
  @Override
99
96
  public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
100
- if(mIsRemoved) {
101
- return;
102
- }
103
97
  surfaceSizeChanged(width, height);
104
98
  }
105
99
 
106
100
  @Override
107
101
  public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
108
- if(mIsRemoved) {
109
- return true;
110
- }
111
102
  surfaceDestroyed();
112
- mSurface.release();
113
- mSurface = null;
114
- return true;
103
+ // https://developer.android.com/reference/android/view/TextureView.SurfaceTextureListener#onSurfaceTextureDestroyed(android.graphics.SurfaceTexture)
104
+ // Invoked when the specified SurfaceTexture is about to be destroyed. If returns true,
105
+ // no rendering should happen inside the surface texture after this method is invoked.
106
+ // If returns false, the client needs to call SurfaceTexture#release().
107
+ return false;
115
108
  }
116
109
 
117
110
  @Override
@@ -39,6 +39,7 @@
39
39
  #include "JsiSkContourMeasureIter.h"
40
40
  #include "JsiSkPictureRecorder.h"
41
41
  #include "JsiSkPictureFactory.h"
42
+ #include "JsiSkColor.h"
42
43
 
43
44
  namespace RNSkia
44
45
  {
@@ -67,6 +68,7 @@ namespace RNSkia
67
68
  installFunction("ContourMeasureIter", JsiSkContourMeasureIter::createCtor(context));
68
69
  installFunction("MakeVertices", JsiSkVertices::createCtor(context));
69
70
  installFunction("PictureRecorder", JsiSkPictureRecorder::createCtor(context));
71
+ installFunction("parseColorString", JsiSkColor::createCtor());
70
72
 
71
73
  // Static members
72
74
  installReadonlyProperty("FontMgr",
@@ -0,0 +1,49 @@
1
+ #pragma once
2
+
3
+ #include <memory>
4
+ #include <utility>
5
+
6
+ #include <jsi/jsi.h>
7
+
8
+ #include "JsiSkHostObjects.h"
9
+ #include "third_party/CSSColorParser.h"
10
+
11
+ #pragma clang diagnostic push
12
+ #pragma clang diagnostic ignored "-Wdocumentation"
13
+
14
+ #include <SkColor.h>
15
+
16
+ #pragma clang diagnostic pop
17
+
18
+ namespace RNSkia {
19
+
20
+ using namespace facebook;
21
+
22
+ class JsiSkColor : public JsiHostObject {
23
+ public:
24
+
25
+ JsiSkColor(): JsiHostObject() {}
26
+
27
+ ~JsiSkColor() {}
28
+
29
+ /**
30
+ * Creates the function for construction a new instance of the SkColor
31
+ * wrapper
32
+ * @return A function for creating a new host object wrapper for the SkColor
33
+ * class
34
+ */
35
+ static const jsi::HostFunctionType
36
+ createCtor() {
37
+ return JSI_HOST_FUNCTION_LAMBDA {
38
+ auto text = arguments[0].asString(runtime).utf8(runtime);
39
+ auto color = CSSColorParser::parse(text);
40
+ if (color.a == -1.0f) {
41
+ return jsi::Value::undefined();
42
+ }
43
+ int a = round(color.a * 255);
44
+ // Because JS numbers are unsigned we need to do this conversion
45
+ return jsi::Value(static_cast<double>(SkColorSetARGB(a, color.r, color.g, color.b) >> 0));
46
+ };
47
+ }
48
+ };
49
+ } // namespace RNSkia
@@ -29,9 +29,9 @@ namespace RNSkia {
29
29
 
30
30
  using namespace facebook;
31
31
 
32
+
32
33
  class JsiSkPath : public JsiSkWrappingSharedPtrHostObject<SkPath> {
33
34
  public:
34
-
35
35
  // TODO: declare in JsiSkWrappingSkPtrHostObject via extra template parameter?
36
36
  JSI_PROPERTY_GET(__typename__) {
37
37
  return jsi::String::createFromUtf8(runtime, "Path");
@@ -484,6 +484,33 @@ public:
484
484
  runtime, std::make_shared<JsiSkPath>(getContext(), std::move(result)));
485
485
  }
486
486
 
487
+ JSI_HOST_FUNCTION(toCmds) {
488
+ auto path = *getObject();
489
+ auto cmds = jsi::Array(runtime, path.countVerbs());
490
+ auto it = SkPath::Iter(path, false);
491
+ // { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
492
+ const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
493
+ const int cmdCount[] = { 3 , 5 , 7 , 8 , 9 , 3 , 0 };
494
+ SkPoint points[4];
495
+ SkPath::Verb verb;
496
+ auto k = 0;
497
+ while (SkPath::kDone_Verb != (verb = it.next(points))) {
498
+ auto verbVal = static_cast<int>(verb);
499
+ auto cmd = jsi::Array(runtime, cmdCount[verbVal]);
500
+ auto j = 0;
501
+ cmd.setValueAtIndex(runtime, j++, jsi::Value(verbVal));
502
+ for (int i = 0; i < pointCount[verbVal]; ++i) {
503
+ cmd.setValueAtIndex(runtime, j++, jsi::Value(static_cast<double>(points[i].fX)));
504
+ cmd.setValueAtIndex(runtime, j++, jsi::Value(static_cast<double>(points[i].fY)));
505
+ }
506
+ if (SkPath::kConic_Verb == verb) {
507
+ cmd.setValueAtIndex(runtime, j, jsi::Value(static_cast<double>(it.conicWeight())));
508
+ }
509
+ cmds.setValueAtIndex(runtime, k++, cmd);
510
+ }
511
+ return cmds;
512
+ }
513
+
487
514
  JSI_EXPORT_PROPERTY_GETTERS(JSI_EXPORT_PROP_GET(JsiSkPath, __typename__))
488
515
 
489
516
  JSI_EXPORT_FUNCTIONS(
@@ -518,7 +545,9 @@ public:
518
545
  JSI_EXPORT_FUNC(JsiSkPath, simplify),
519
546
  JSI_EXPORT_FUNC(JsiSkPath, countPoints), JSI_EXPORT_FUNC(JsiSkPath, copy),
520
547
  JSI_EXPORT_FUNC(JsiSkPath, fromText), JSI_EXPORT_FUNC(JsiSkPath, op),
521
- JSI_EXPORT_FUNC(JsiSkPath, isInterpolatable), JSI_EXPORT_FUNC(JsiSkPath, interpolate)
548
+ JSI_EXPORT_FUNC(JsiSkPath, isInterpolatable),
549
+ JSI_EXPORT_FUNC(JsiSkPath, interpolate),
550
+ JSI_EXPORT_FUNC(JsiSkPath, toCmds),
522
551
  )
523
552
 
524
553
  JsiSkPath(std::shared_ptr<RNSkPlatformContext> context, SkPath path)
@@ -13,6 +13,7 @@
13
13
 
14
14
  #include <SkPath.h>
15
15
  #include <SkPathOps.h>
16
+ #include <RNSkLog.h>
16
17
 
17
18
  #pragma clang diagnostic pop
18
19
 
@@ -21,6 +22,14 @@ namespace RNSkia {
21
22
  using namespace facebook;
22
23
 
23
24
  class JsiSkPathFactory : public JsiSkHostObject {
25
+
26
+ static const int MOVE = 0;
27
+ static const int LINE = 1;
28
+ static const int QUAD = 2;
29
+ static const int CONIC = 3;
30
+ static const int CUBIC = 4;
31
+ static const int CLOSE = 5;
32
+
24
33
  public:
25
34
  JSI_HOST_FUNCTION(Make) {
26
35
  return jsi::Object::createFromHostObject(
@@ -53,9 +62,95 @@ public:
53
62
  runtime, std::make_shared<JsiSkPath>(getContext(), std::move(result)));
54
63
  }
55
64
 
65
+ JSI_HOST_FUNCTION(MakeFromCmds) {
66
+ SkPath path;
67
+ auto cmds = arguments[0].asObject(runtime).asArray(runtime);
68
+ auto cmdCount = cmds.size(runtime);
69
+ for (int i = 0; i < cmdCount; i++) {
70
+ auto cmd = cmds.getValueAtIndex(runtime, i).asObject(runtime).asArray(runtime);
71
+ if (cmd.size(runtime) < 1) {
72
+ RNSkLogger::logToConsole("Invalid command found (got an empty array)");
73
+ return jsi::Value::null();
74
+ }
75
+ auto verb = static_cast<int>(cmd.getValueAtIndex(runtime, 0).asNumber());
76
+ switch (verb) {
77
+ case MOVE: {
78
+ if (cmd.size(runtime) < 3) {
79
+ RNSkLogger::logToConsole( "Invalid move command found");
80
+ return jsi::Value::null();
81
+ }
82
+ auto x = cmd.getValueAtIndex(runtime, 1).asNumber();
83
+ auto y = cmd.getValueAtIndex(runtime, 2).asNumber();
84
+ path.moveTo(x, y);
85
+ break;
86
+ }
87
+ case LINE: {
88
+ if (cmd.size(runtime) < 3) {
89
+ RNSkLogger::logToConsole("Invalid line command found");
90
+ return jsi::Value::null();
91
+ }
92
+ auto x = cmd.getValueAtIndex(runtime, 1).asNumber();
93
+ auto y = cmd.getValueAtIndex(runtime, 2).asNumber();
94
+ path.lineTo(x, y);
95
+ break;
96
+ }
97
+ case QUAD: {
98
+ if (cmd.size(runtime) < 5) {
99
+ RNSkLogger::logToConsole("Invalid line command found");
100
+ return jsi::Value::null();
101
+ }
102
+ auto x1 = cmd.getValueAtIndex(runtime, 1).asNumber();
103
+ auto y1 = cmd.getValueAtIndex(runtime, 2).asNumber();
104
+ auto x2 = cmd.getValueAtIndex(runtime, 3).asNumber();
105
+ auto y2 = cmd.getValueAtIndex(runtime, 4).asNumber();
106
+ path.quadTo(x1, y1, x2, y2);
107
+ break;
108
+ }
109
+ case CONIC: {
110
+ if (cmd.size(runtime) < 6) {
111
+ RNSkLogger::logToConsole("Invalid line command found");
112
+ return jsi::Value::null();
113
+ }
114
+ auto x1 = cmd.getValueAtIndex(runtime, 1).asNumber();
115
+ auto y1 = cmd.getValueAtIndex(runtime, 2).asNumber();
116
+ auto x2 = cmd.getValueAtIndex(runtime, 3).asNumber();
117
+ auto y2 = cmd.getValueAtIndex(runtime, 4).asNumber();
118
+ auto w = cmd.getValueAtIndex(runtime, 5).asNumber();
119
+ path.conicTo(x1, y1, x2, y2, w);
120
+ break;
121
+ }
122
+ case CUBIC: {
123
+ if (cmd.size(runtime) < 7) {
124
+ RNSkLogger::logToConsole("Invalid line command found");
125
+ return jsi::Value::null();
126
+ }
127
+ auto x1 = cmd.getValueAtIndex(runtime, 1).asNumber();
128
+ auto y1 = cmd.getValueAtIndex(runtime, 2).asNumber();
129
+ auto x2 = cmd.getValueAtIndex(runtime, 3).asNumber();
130
+ auto y2 = cmd.getValueAtIndex(runtime, 4).asNumber();
131
+ auto x3 = cmd.getValueAtIndex(runtime, 5).asNumber();
132
+ auto y3 = cmd.getValueAtIndex(runtime, 6).asNumber();
133
+ path.cubicTo(x1, y1, x2, y2, x3, y3);
134
+ break;
135
+ }
136
+ case CLOSE: {
137
+ path.close();
138
+ break;
139
+ }
140
+ default: {
141
+ RNSkLogger::logToConsole("Found an unknown command");
142
+ return jsi::Value::null();
143
+ }
144
+ }
145
+ }
146
+ return jsi::Object::createFromHostObject(
147
+ runtime, std::make_shared<JsiSkPath>(getContext(), std::move(path)));
148
+ }
149
+
56
150
  JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkPathFactory, Make),
57
151
  JSI_EXPORT_FUNC(JsiSkPathFactory, MakeFromSVGString),
58
- JSI_EXPORT_FUNC(JsiSkPathFactory, MakeFromOp))
152
+ JSI_EXPORT_FUNC(JsiSkPathFactory, MakeFromOp),
153
+ JSI_EXPORT_FUNC(JsiSkPathFactory, MakeFromCmds))
59
154
 
60
155
  JsiSkPathFactory(std::shared_ptr<RNSkPlatformContext> context)
61
156
  : JsiSkHostObject(std::move(context)) {}