@shopify/react-native-skia 1.10.2 → 1.11.1

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 (104) hide show
  1. package/cpp/api/JsiSkApi.h +3 -0
  2. package/cpp/api/recorder/ColorFilters.h +133 -0
  3. package/cpp/api/recorder/Command.h +58 -0
  4. package/cpp/api/recorder/Convertor.h +1213 -0
  5. package/cpp/api/recorder/DataTypes.h +232 -0
  6. package/cpp/api/recorder/DrawingCtx.h +187 -0
  7. package/cpp/api/recorder/Drawings.h +950 -0
  8. package/cpp/api/recorder/ImageFilters.h +292 -0
  9. package/cpp/api/recorder/ImageFit.h +108 -0
  10. package/cpp/api/recorder/JsiRecorder.h +314 -0
  11. package/cpp/api/recorder/Paint.h +191 -0
  12. package/cpp/api/recorder/PathEffects.h +194 -0
  13. package/cpp/api/recorder/RNRecorder.h +637 -0
  14. package/cpp/api/recorder/Shaders.h +406 -0
  15. package/cpp/rnskia/dom/nodes/JsiAtlasNode.h +3 -2
  16. package/cpp/rnskia/dom/nodes/JsiImageNode.h +3 -2
  17. package/jestSetup.js +8 -0
  18. package/jestSetup.mjs +8 -0
  19. package/lib/commonjs/renderer/components/image/Image.d.ts +1 -1
  20. package/lib/commonjs/renderer/components/image/Image.js +8 -2
  21. package/lib/commonjs/renderer/components/image/Image.js.map +1 -1
  22. package/lib/commonjs/skia/types/Recorder.d.ts +52 -0
  23. package/lib/commonjs/skia/types/Recorder.js +6 -0
  24. package/lib/commonjs/skia/types/Recorder.js.map +1 -0
  25. package/lib/commonjs/skia/types/Skia.d.ts +2 -0
  26. package/lib/commonjs/skia/types/Skia.js.map +1 -1
  27. package/lib/commonjs/skia/types/index.d.ts +1 -0
  28. package/lib/commonjs/skia/types/index.js +11 -0
  29. package/lib/commonjs/skia/types/index.js.map +1 -1
  30. package/lib/commonjs/skia/web/JsiSkia.js +3 -0
  31. package/lib/commonjs/skia/web/JsiSkia.js.map +1 -1
  32. package/lib/commonjs/sksg/Container.d.ts +6 -1
  33. package/lib/commonjs/sksg/Container.js +59 -2
  34. package/lib/commonjs/sksg/Container.js.map +1 -1
  35. package/lib/commonjs/sksg/Recorder/DrawingContext.js +1 -0
  36. package/lib/commonjs/sksg/Recorder/DrawingContext.js.map +1 -1
  37. package/lib/commonjs/sksg/Recorder/ReanimatedRecorder.d.ts +53 -0
  38. package/lib/commonjs/sksg/Recorder/ReanimatedRecorder.js +189 -0
  39. package/lib/commonjs/sksg/Recorder/ReanimatedRecorder.js.map +1 -0
  40. package/lib/commonjs/sksg/Recorder/Recorder.d.ts +2 -2
  41. package/lib/commonjs/sksg/Recorder/Recorder.js.map +1 -1
  42. package/lib/commonjs/sksg/Recorder/Visitor.d.ts +2 -2
  43. package/lib/commonjs/sksg/Recorder/Visitor.js +2 -2
  44. package/lib/commonjs/sksg/Recorder/Visitor.js.map +1 -1
  45. package/lib/module/renderer/components/image/Image.d.ts +1 -1
  46. package/lib/module/renderer/components/image/Image.js +8 -2
  47. package/lib/module/renderer/components/image/Image.js.map +1 -1
  48. package/lib/module/skia/types/Recorder.d.ts +52 -0
  49. package/lib/module/skia/types/Recorder.js +2 -0
  50. package/lib/module/skia/types/Recorder.js.map +1 -0
  51. package/lib/module/skia/types/Skia.d.ts +2 -0
  52. package/lib/module/skia/types/Skia.js.map +1 -1
  53. package/lib/module/skia/types/index.d.ts +1 -0
  54. package/lib/module/skia/types/index.js +1 -0
  55. package/lib/module/skia/types/index.js.map +1 -1
  56. package/lib/module/skia/web/JsiSkia.js +3 -0
  57. package/lib/module/skia/web/JsiSkia.js.map +1 -1
  58. package/lib/module/sksg/Container.d.ts +6 -1
  59. package/lib/module/sksg/Container.js +59 -2
  60. package/lib/module/sksg/Container.js.map +1 -1
  61. package/lib/module/sksg/Recorder/DrawingContext.js +1 -0
  62. package/lib/module/sksg/Recorder/DrawingContext.js.map +1 -1
  63. package/lib/module/sksg/Recorder/ReanimatedRecorder.d.ts +53 -0
  64. package/lib/module/sksg/Recorder/ReanimatedRecorder.js +182 -0
  65. package/lib/module/sksg/Recorder/ReanimatedRecorder.js.map +1 -0
  66. package/lib/module/sksg/Recorder/Recorder.d.ts +2 -2
  67. package/lib/module/sksg/Recorder/Recorder.js.map +1 -1
  68. package/lib/module/sksg/Recorder/Visitor.d.ts +2 -2
  69. package/lib/module/sksg/Recorder/Visitor.js +2 -2
  70. package/lib/module/sksg/Recorder/Visitor.js.map +1 -1
  71. package/lib/typescript/lib/commonjs/renderer/components/image/Image.d.ts +4 -1
  72. package/lib/typescript/lib/commonjs/skia/types/Recorder.d.ts +1 -0
  73. package/lib/typescript/lib/commonjs/skia/web/JsiSkia.d.ts +1 -0
  74. package/lib/typescript/lib/commonjs/sksg/Container.d.ts +5 -1
  75. package/lib/typescript/lib/commonjs/sksg/Reconciler.d.ts +6 -0
  76. package/lib/typescript/lib/commonjs/sksg/Recorder/ReanimatedRecorder.d.ts +47 -0
  77. package/lib/typescript/lib/module/mock/index.d.ts +4 -1
  78. package/lib/typescript/lib/module/renderer/components/image/Image.d.ts +4 -1
  79. package/lib/typescript/lib/module/skia/Skia.web.d.ts +1 -0
  80. package/lib/typescript/lib/module/skia/types/Recorder.d.ts +1 -0
  81. package/lib/typescript/lib/module/skia/types/index.d.ts +1 -0
  82. package/lib/typescript/lib/module/skia/web/JsiSkia.d.ts +1 -0
  83. package/lib/typescript/lib/module/sksg/Container.d.ts +5 -1
  84. package/lib/typescript/lib/module/sksg/Reconciler.d.ts +6 -0
  85. package/lib/typescript/lib/module/sksg/Recorder/ReanimatedRecorder.d.ts +46 -0
  86. package/lib/typescript/src/renderer/components/image/Image.d.ts +1 -1
  87. package/lib/typescript/src/skia/types/Recorder.d.ts +52 -0
  88. package/lib/typescript/src/skia/types/Skia.d.ts +2 -0
  89. package/lib/typescript/src/skia/types/index.d.ts +1 -0
  90. package/lib/typescript/src/sksg/Container.d.ts +6 -1
  91. package/lib/typescript/src/sksg/Recorder/ReanimatedRecorder.d.ts +53 -0
  92. package/lib/typescript/src/sksg/Recorder/Recorder.d.ts +2 -2
  93. package/lib/typescript/src/sksg/Recorder/Visitor.d.ts +2 -2
  94. package/package.json +3 -2
  95. package/src/renderer/components/image/Image.tsx +2 -2
  96. package/src/skia/types/Recorder.ts +91 -0
  97. package/src/skia/types/Skia.ts +2 -0
  98. package/src/skia/types/index.ts +1 -0
  99. package/src/skia/web/JsiSkia.ts +3 -0
  100. package/src/sksg/Container.ts +63 -4
  101. package/src/sksg/Recorder/DrawingContext.ts +1 -0
  102. package/src/sksg/Recorder/ReanimatedRecorder.ts +271 -0
  103. package/src/sksg/Recorder/Recorder.ts +2 -2
  104. package/src/sksg/Recorder/Visitor.ts +17 -12
@@ -0,0 +1,1213 @@
1
+ #pragma once
2
+
3
+ #include <functional>
4
+ #include <map>
5
+ #include <optional>
6
+ #include <variant>
7
+ #include <vector>
8
+
9
+ #include <include/core/SkBlurTypes.h>
10
+ #include <include/core/SkPaint.h>
11
+ #include <include/core/SkPathEffect.h>
12
+ #include <include/core/SkPoint.h>
13
+ #include <include/effects/SkRuntimeEffect.h>
14
+ #include <modules/skparagraph/include/Paragraph.h>
15
+ #include <modules/skparagraph/include/ParagraphBuilder.h>
16
+ #include <modules/skparagraph/include/ParagraphStyle.h>
17
+
18
+ #include "third_party/CSSColorParser.h"
19
+
20
+ #include "DataTypes.h"
21
+
22
+ #include <jsi/jsi.h>
23
+
24
+ namespace RNSkia {
25
+
26
+ struct Radius {
27
+ float rX;
28
+ float rY;
29
+ };
30
+
31
+ using ConversionFunction =
32
+ std::function<void(jsi::Runtime &runtime, const jsi::Object &object)>;
33
+ using Variables = std::map<std::string, std::vector<ConversionFunction>>;
34
+ using Patch = std::array<SkPoint, 12>;
35
+
36
+ bool isSharedValue(jsi::Runtime &runtime, const jsi::Value &value) {
37
+ return value.isObject() &&
38
+ value.asObject(runtime).hasProperty(runtime,
39
+ "_isReanimatedSharedValue") &&
40
+ value.asObject(runtime)
41
+ .getProperty(runtime, "_isReanimatedSharedValue")
42
+ .isBool() &&
43
+ value.asObject(runtime)
44
+ .getProperty(runtime, "_isReanimatedSharedValue")
45
+ .asBool() == true;
46
+ }
47
+
48
+ // Helper type traits
49
+ template <typename T> struct is_optional : std::false_type {};
50
+
51
+ template <typename T> struct is_optional<std::optional<T>> : std::true_type {};
52
+
53
+ template <typename T> struct unwrap_optional {
54
+ using type = T;
55
+ };
56
+
57
+ template <typename T> struct unwrap_optional<std::optional<T>> {
58
+ using type = T;
59
+ };
60
+
61
+ // Property value getter declarations
62
+ template <typename T>
63
+ T getPropertyValue(jsi::Runtime &runtime, const jsi::Value &value);
64
+
65
+ // Base template for convertProperty
66
+ template <typename T, typename Target>
67
+ void convertPropertyImpl(jsi::Runtime &runtime, const jsi::Object &object,
68
+ const std::string &propertyName, Target &target,
69
+ Variables &variables) {
70
+ if (!object.hasProperty(runtime, propertyName.c_str())) {
71
+ return;
72
+ }
73
+
74
+ auto property = object.getProperty(runtime, propertyName.c_str());
75
+
76
+ if (isSharedValue(runtime, property)) {
77
+ auto sharedValue = property.asObject(runtime);
78
+ auto name = sharedValue.getProperty(runtime, "name")
79
+ .asString(runtime)
80
+ .utf8(runtime);
81
+ auto conv = [target = &target](jsi::Runtime &runtime,
82
+ const jsi::Object &val) {
83
+ auto value = val.getProperty(runtime, "value");
84
+ *target = getPropertyValue<T>(runtime, value);
85
+ };
86
+ variables[name].push_back(conv);
87
+ conv(runtime, sharedValue);
88
+ } else {
89
+ target = getPropertyValue<T>(runtime, property);
90
+ }
91
+ }
92
+
93
+ // Main convertProperty template
94
+ template <typename T>
95
+ void convertProperty(jsi::Runtime &runtime, const jsi::Object &object,
96
+ const std::string &propertyName, T &target,
97
+ Variables &variables) {
98
+ convertPropertyImpl<T>(runtime, object, propertyName, target, variables);
99
+ }
100
+
101
+ // Base property value getter implementations
102
+ template <>
103
+ float getPropertyValue(jsi::Runtime &runtime, const jsi::Value &value) {
104
+ if (value.isNumber()) {
105
+ return static_cast<float>(value.asNumber());
106
+ }
107
+ throw std::runtime_error("Invalid float prop value received");
108
+ }
109
+
110
+ template <>
111
+ int getPropertyValue(jsi::Runtime &runtime, const jsi::Value &value) {
112
+ if (value.isNumber()) {
113
+ return static_cast<int>(value.asNumber());
114
+ }
115
+ throw std::runtime_error("Invalid int prop value received");
116
+ }
117
+
118
+ template <>
119
+ std::string getPropertyValue(jsi::Runtime &runtime, const jsi::Value &value) {
120
+ if (value.isString()) {
121
+ return value.asString(runtime).utf8(runtime);
122
+ }
123
+ throw std::runtime_error("Invalid string prop value received");
124
+ }
125
+
126
+ template <>
127
+ SkPoint getPropertyValue(jsi::Runtime &runtime, const jsi::Value &value) {
128
+ if (value.isObject()) {
129
+ auto x = value.asObject(runtime).getProperty(runtime, "x").asNumber();
130
+ auto y = value.asObject(runtime).getProperty(runtime, "y").asNumber();
131
+ return SkPoint::Make(x, y);
132
+ }
133
+ throw std::runtime_error("Invalid prop value for SkPoint received");
134
+ }
135
+
136
+ template <>
137
+ SkColor getPropertyValue(jsi::Runtime &runtime, const jsi::Value &value) {
138
+ if (value.isNumber()) {
139
+ return static_cast<SkColor>(value.asNumber());
140
+ } else if (value.isString()) {
141
+ auto text = value.asString(runtime).utf8(runtime);
142
+ auto color = CSSColorParser::parse(text);
143
+ if (color.a == -1.0f) {
144
+ return SK_ColorBLACK;
145
+ }
146
+ return SkColorSetARGB(color.a * 255, color.r, color.g, color.b);
147
+ } else if (value.isObject()) {
148
+ const auto &object = value.asObject(runtime);
149
+ if (object.isArray(runtime)) {
150
+ auto array = object.asArray(runtime);
151
+ auto r = array.getValueAtIndex(runtime, 0).asNumber();
152
+ auto g = array.getValueAtIndex(runtime, 1).asNumber();
153
+ auto b = array.getValueAtIndex(runtime, 2).asNumber();
154
+ auto a = array.getValueAtIndex(runtime, 3).asNumber();
155
+ return SkColorSetARGB(a * 255, r * 255, g * 255, b * 255);
156
+ }
157
+ jsi::ArrayBuffer buffer =
158
+ object
159
+ .getProperty(runtime, jsi::PropNameID::forAscii(runtime, "buffer"))
160
+ .asObject(runtime)
161
+ .getArrayBuffer(runtime);
162
+ auto bfrPtr = reinterpret_cast<float *>(buffer.data(runtime));
163
+ if (bfrPtr[0] > 1 || bfrPtr[1] > 1 || bfrPtr[2] > 1 || bfrPtr[3] > 1) {
164
+ return SK_ColorBLACK;
165
+ }
166
+ return SkColorSetARGB(bfrPtr[3] * 255, bfrPtr[0] * 255, bfrPtr[1] * 255,
167
+ bfrPtr[2] * 255);
168
+ }
169
+ throw std::runtime_error("Invalid prop value for SkColor received");
170
+ }
171
+
172
+ template <>
173
+ std::vector<SkColor> getPropertyValue(jsi::Runtime &runtime,
174
+ const jsi::Value &value) {
175
+ std::vector<SkColor> result;
176
+ if (value.isObject() && value.asObject(runtime).isArray(runtime)) {
177
+ auto array = value.asObject(runtime).asArray(runtime);
178
+ size_t size = array.size(runtime);
179
+ result.reserve(size);
180
+
181
+ for (size_t i = 0; i < size; i++) {
182
+ result.push_back(getPropertyValue<SkColor>(
183
+ runtime, array.getValueAtIndex(runtime, i)));
184
+ }
185
+ }
186
+ return result;
187
+ }
188
+
189
+ template <>
190
+ SkTileMode getPropertyValue(jsi::Runtime &runtime, const jsi::Value &val) {
191
+ if (val.isString()) {
192
+ auto value = val.asString(runtime).utf8(runtime);
193
+ if (value == "clamp") {
194
+ return SkTileMode::kClamp;
195
+ } else if (value == "repeat") {
196
+ return SkTileMode::kRepeat;
197
+ } else if (value == "mirror") {
198
+ return SkTileMode::kMirror;
199
+ } else if (value == "decal") {
200
+ return SkTileMode::kDecal;
201
+ }
202
+ }
203
+ throw std::runtime_error("Invalid value for SkTileMode received");
204
+ }
205
+
206
+ template <>
207
+ SkColorChannel getPropertyValue(jsi::Runtime &runtime, const jsi::Value &val) {
208
+ if (val.isString()) {
209
+ auto value = val.asString(runtime).utf8(runtime);
210
+ if (value == "r") {
211
+ return SkColorChannel::kR;
212
+ } else if (value == "b") {
213
+ return SkColorChannel::kB;
214
+ } else if (value == "g") {
215
+ return SkColorChannel::kG;
216
+ } else if (value == "a") {
217
+ return SkColorChannel::kA;
218
+ }
219
+ }
220
+ throw std::runtime_error("Invalid value for SkTileMode received");
221
+ }
222
+
223
+ template <>
224
+ SkVertices::VertexMode getPropertyValue(jsi::Runtime &runtime,
225
+ const jsi::Value &val) {
226
+ if (val.isString()) {
227
+ auto value = val.asString(runtime).utf8(runtime);
228
+ if (value == "triangles") {
229
+ return SkVertices::VertexMode::kTriangles_VertexMode;
230
+ } else if (value == "triangleStrip") {
231
+ return SkVertices::VertexMode::kTriangleStrip_VertexMode;
232
+ } else if (value == "triangleFan") {
233
+ return SkVertices::VertexMode::kTriangleFan_VertexMode;
234
+ }
235
+ }
236
+ throw std::runtime_error("Invalid value for VertexMode received");
237
+ }
238
+
239
+ template <>
240
+ SkM44 getPropertyValue(jsi::Runtime &runtime, const jsi::Value &value) {
241
+ if (value.isObject()) {
242
+ auto object = value.asObject(runtime);
243
+ // Get array of property names
244
+ auto array = object.asArray(runtime);
245
+ auto size = array.size(runtime);
246
+ SkM44 m4;
247
+ for (int i = 0; i < size; i++) {
248
+ auto value = array.getValueAtIndex(runtime, i).asObject(runtime);
249
+ auto propNames = value.getPropertyNames(runtime);
250
+ if (propNames.size(runtime) == 0) {
251
+ throw std::runtime_error(
252
+ "Empty value in transform. Expected translateX, translateY, "
253
+ "scale, "
254
+ "scaleX, scaleY, skewX, skewY, rotate or rotateZ.");
255
+ }
256
+ auto key =
257
+ propNames.getValueAtIndex(runtime, 0).asString(runtime).utf8(runtime);
258
+ if (key == "translateX") {
259
+ auto x = value.getProperty(runtime, key.c_str()).asNumber();
260
+ m4.preTranslate(x, 0, 0);
261
+ } else if (key == "translateY") {
262
+ auto y = value.getProperty(runtime, key.c_str()).asNumber();
263
+ m4.preTranslate(0, y, 0);
264
+ } else if (key == "translateZ") {
265
+ auto z = value.getProperty(runtime, key.c_str()).asNumber();
266
+ m4.preTranslate(0, 0, z);
267
+ } else if (key == "translate") {
268
+ auto arr = value.getProperty(runtime, key.c_str())
269
+ .asObject(runtime)
270
+ .asArray(runtime);
271
+ double x = 0, y = 0, z = 0;
272
+ for (int i = 0; i < arr.size(runtime); i++) {
273
+ if (i == 0) {
274
+ x = arr.getValueAtIndex(runtime, i).asNumber();
275
+ } else if (i == 1) {
276
+ y = arr.getValueAtIndex(runtime, i).asNumber();
277
+ } else if (i == 2) {
278
+ z = arr.getValueAtIndex(runtime, i).asNumber();
279
+ }
280
+ }
281
+ m4.preTranslate(x, y, z);
282
+ } else if (key == "scale") {
283
+ auto s = value.getProperty(runtime, key.c_str()).asNumber();
284
+ m4.preScale(s, s);
285
+ } else if (key == "scaleX") {
286
+ auto s = value.getProperty(runtime, key.c_str()).asNumber();
287
+ m4.preScale(s, 1);
288
+ } else if (key == "scaleY") {
289
+ auto s = value.getProperty(runtime, key.c_str()).asNumber();
290
+ m4.preScale(1, s);
291
+ } else if (key == "skewX") {
292
+ auto angle = value.getProperty(runtime, key.c_str()).asNumber();
293
+ SkM44 skewX(1, 0, 0, 0, std::tan(angle), 1, 0, 0, 0, 0, 1, 0, 0, 0, 0,
294
+ 1);
295
+ m4.preConcat(skewX);
296
+
297
+ } else if (key == "skewY") {
298
+ auto angle = value.getProperty(runtime, key.c_str()).asNumber();
299
+ SkM44 skewY(1, std::tan(angle), 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0,
300
+ 1);
301
+ m4.preConcat(skewY);
302
+ } else if (key == "rotate" || key == "rotateZ") {
303
+ auto angle = value.getProperty(runtime, key.c_str()).asNumber();
304
+ SkM44 rotate;
305
+ rotate.setRotateUnit({0, 0, 1}, angle);
306
+ m4.preConcat(rotate);
307
+ } else if (key == "rotateY") {
308
+ auto angle = value.getProperty(runtime, key.c_str()).asNumber();
309
+ SkM44 rotate;
310
+ rotate.setRotateUnit({0, 1, 0}, angle);
311
+ m4.preConcat(rotate);
312
+ } else if (key == "rotateX") {
313
+ auto angle = value.getProperty(runtime, key.c_str()).asNumber();
314
+ SkM44 rotate;
315
+ rotate.setRotateUnit({1, 0, 0}, angle);
316
+ m4.preConcat(rotate);
317
+ } else if (key == "perspective") {
318
+ auto p = value.getProperty(runtime, key.c_str()).asNumber();
319
+ SkM44 perspective(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, -1 / p, 1);
320
+ m4.preConcat(perspective);
321
+ } else if (key == "matrix") {
322
+ auto arr = value.getProperty(runtime, key.c_str())
323
+ .asObject(runtime)
324
+ .asArray(runtime);
325
+ SkM44 m44;
326
+ for (size_t i = 0; i < arr.size(runtime); ++i) {
327
+ auto obj = arr.getValueAtIndex(runtime, i);
328
+ m44.setRC(i / 4, i % 4, obj.asNumber());
329
+ }
330
+ m4.preConcat(m44);
331
+ } else {
332
+ throw std::runtime_error(
333
+ "Unknown key in transform. Expected translateX, translateY, "
334
+ "scale, "
335
+ "scaleX, scaleY, skewX, skewY, rotate or rotateZ - got " +
336
+ std::string(key) + ".");
337
+ }
338
+ }
339
+ return m4;
340
+ }
341
+ throw std::runtime_error("Invalid prop value for SkM44 received");
342
+ }
343
+
344
+ template <>
345
+ SkSamplingOptions getPropertyValue(jsi::Runtime &runtime,
346
+ const jsi::Value &value) {
347
+ if (value.isObject()) {
348
+ SkSamplingOptions samplingOptions(SkFilterMode::kLinear);
349
+ auto object = value.asObject(runtime);
350
+ if (object.hasProperty(runtime, "B") && object.hasProperty(runtime, "C")) {
351
+ auto B = static_cast<float>(object.getProperty(runtime, "B").asNumber());
352
+ auto C = static_cast<float>(object.getProperty(runtime, "C").asNumber());
353
+ samplingOptions = SkSamplingOptions({B, C});
354
+ } else if (object.hasProperty(runtime, "filter")) {
355
+ auto filter = static_cast<SkFilterMode>(
356
+ object.getProperty(runtime, "filter").asNumber());
357
+ if (object.hasProperty(runtime, "mipmap")) {
358
+ auto mipmap = static_cast<SkMipmapMode>(
359
+ object.getProperty(runtime, "mipmap").asNumber());
360
+ samplingOptions = SkSamplingOptions(filter, mipmap);
361
+ } else {
362
+ samplingOptions = SkSamplingOptions(filter);
363
+ }
364
+ }
365
+ return samplingOptions;
366
+ }
367
+
368
+ throw std::runtime_error("Invalid prop value for SkSamplingOptions received");
369
+ }
370
+
371
+ template <>
372
+ SkFont getPropertyValue(jsi::Runtime &runtime, const jsi::Value &value) {
373
+ if (value.isObject()) {
374
+ auto font =
375
+ value.asObject(runtime).asHostObject<JsiSkFont>(runtime)->getObject();
376
+ return SkFont(*font);
377
+ }
378
+ throw std::runtime_error("Invalid prop value for SkFont received");
379
+ }
380
+
381
+ template <>
382
+ SkRSXform getPropertyValue(jsi::Runtime &runtime, const jsi::Value &value) {
383
+ if (value.isObject()) {
384
+ auto form = value.asObject(runtime)
385
+ .asHostObject<JsiSkRSXform>(runtime)
386
+ ->getObject();
387
+ return SkRSXform::Make(form->fSCos, form->fSSin, form->fTx, form->fTy);
388
+ }
389
+ throw std::runtime_error("Invalid prop value for SkRSXform received");
390
+ }
391
+
392
+ template <>
393
+ sk_sp<SkPicture> getPropertyValue(jsi::Runtime &runtime,
394
+ const jsi::Value &value) {
395
+ if (value.isObject()) {
396
+ auto picture = value.asObject(runtime)
397
+ .asHostObject<JsiSkPicture>(runtime)
398
+ ->getObject();
399
+ return picture;
400
+ }
401
+ throw std::runtime_error("Invalid prop value for SkTextBlob received");
402
+ }
403
+
404
+ template <>
405
+ SkPaint getPropertyValue(jsi::Runtime &runtime, const jsi::Value &value) {
406
+ if (value.isObject()) {
407
+ auto paint =
408
+ value.asObject(runtime).asHostObject<JsiSkPaint>(runtime)->getObject();
409
+ return SkPaint(*paint);
410
+ }
411
+ throw std::runtime_error("Invalid prop value for SkPaint received");
412
+ }
413
+
414
+ template <>
415
+ para::Paragraph *getPropertyValue(jsi::Runtime &runtime,
416
+ const jsi::Value &value) {
417
+ if (value.isObject()) {
418
+ auto para = value.asObject(runtime)
419
+ .asHostObject<JsiSkParagraph>(runtime)
420
+ ->getParagraph();
421
+ return para;
422
+ }
423
+ if (value.isNull()) {
424
+ return nullptr;
425
+ }
426
+ throw std::runtime_error("Invalid prop value for Paragraph received");
427
+ }
428
+
429
+ template <>
430
+ sk_sp<SkTextBlob> getPropertyValue(jsi::Runtime &runtime,
431
+ const jsi::Value &value) {
432
+ if (value.isObject()) {
433
+ auto blob = value.asObject(runtime)
434
+ .asHostObject<JsiSkTextBlob>(runtime)
435
+ ->getObject();
436
+ return blob;
437
+ }
438
+ throw std::runtime_error("Invalid prop value for SkTextBlob received");
439
+ }
440
+
441
+ template <>
442
+ sk_sp<SkRuntimeEffect> getPropertyValue(jsi::Runtime &runtime,
443
+ const jsi::Value &value) {
444
+ if (value.isObject()) {
445
+ auto effect = value.asObject(runtime)
446
+ .asHostObject<JsiSkRuntimeEffect>(runtime)
447
+ ->getObject();
448
+ return effect;
449
+ }
450
+ throw std::runtime_error("Invalid prop value for SkRuntimeEffect received");
451
+ }
452
+
453
+ template <>
454
+ sk_sp<SkImage> getPropertyValue(jsi::Runtime &runtime,
455
+ const jsi::Value &value) {
456
+
457
+ if (value.isObject()) {
458
+ auto effect =
459
+ value.asObject(runtime).asHostObject<JsiSkImage>(runtime)->getObject();
460
+ return effect;
461
+ } else if (value.isNull()) {
462
+ return nullptr;
463
+ }
464
+ throw std::runtime_error("Invalid prop value for SkImage received");
465
+ }
466
+
467
+ template <>
468
+ SkMatrix getPropertyValue(jsi::Runtime &runtime, const jsi::Value &value) {
469
+ if (value.isObject()) {
470
+ auto object = value.asObject(runtime);
471
+
472
+ if (object.isHostObject(runtime)) {
473
+ auto matrix =
474
+ object.asHostObject<JsiSkMatrix>(runtime)->getObject().get();
475
+ return SkMatrix(*matrix);
476
+ } else {
477
+ return JsiSkMatrix::getMatrix(runtime, value);
478
+ }
479
+ }
480
+ throw std::runtime_error("Invalid prop value for SkMatrix received");
481
+ }
482
+
483
+ template <>
484
+ Radius getPropertyValue(jsi::Runtime &runtime, const jsi::Value &value) {
485
+ if (value.isObject()) {
486
+ auto object = value.asObject(runtime);
487
+ auto rX = static_cast<float>(object.getProperty(runtime, "x").asNumber());
488
+ auto rY = static_cast<float>(object.getProperty(runtime, "y").asNumber());
489
+ return {rX, rY};
490
+ } else if (value.isNumber()) {
491
+ auto r = static_cast<float>(value.asNumber());
492
+ return {r, r};
493
+ }
494
+ throw std::runtime_error("Invalid prop value for Radius received");
495
+ }
496
+
497
+ template <>
498
+ SkCanvas::PointMode getPropertyValue(jsi::Runtime &runtime,
499
+ const jsi::Value &val) {
500
+ if (val.isString()) {
501
+ auto value = val.asString(runtime).utf8(runtime);
502
+ if (value == "points") {
503
+ return SkCanvas::PointMode::kPoints_PointMode;
504
+ } else if (value == "lines") {
505
+ return SkCanvas::PointMode::kLines_PointMode;
506
+ } else if (value == "polygon") {
507
+ return SkCanvas::PointMode::kPolygon_PointMode;
508
+ }
509
+ }
510
+ throw std::runtime_error(
511
+ "Invalid prop value for SkCanvas::PointMode received");
512
+ }
513
+
514
+ template <>
515
+ SkPaint::Style getPropertyValue(jsi::Runtime &runtime, const jsi::Value &val) {
516
+ if (val.isString()) {
517
+ auto value = val.asString(runtime).utf8(runtime);
518
+ if (value == "fill") {
519
+ return SkPaint::kFill_Style;
520
+ } else if (value == "stroke") {
521
+ return SkPaint::kStroke_Style;
522
+ }
523
+ }
524
+ throw std::runtime_error("Invalid prop value for SkPaint::Style received");
525
+ }
526
+
527
+ template <>
528
+ SkPaint::Join getPropertyValue(jsi::Runtime &runtime, const jsi::Value &val) {
529
+ if (val.isString()) {
530
+ auto value = val.asString(runtime).utf8(runtime);
531
+ if (value == "miter") {
532
+ return SkPaint::kMiter_Join;
533
+ } else if (value == "round") {
534
+ return SkPaint::kRound_Join;
535
+ } else if (value == "bevel") {
536
+ return SkPaint::kBevel_Join;
537
+ }
538
+ }
539
+ throw std::runtime_error("Invalid prop value for SkPaint::Join received");
540
+ }
541
+
542
+ template <>
543
+ SkPaint::Cap getPropertyValue(jsi::Runtime &runtime, const jsi::Value &val) {
544
+ if (val.isString()) {
545
+ auto value = val.asString(runtime).utf8(runtime);
546
+ if (value == "butt") {
547
+ return SkPaint::kButt_Cap;
548
+ } else if (value == "round") {
549
+ return SkPaint::kRound_Cap;
550
+ } else if (value == "square") {
551
+ return SkPaint::kSquare_Cap;
552
+ }
553
+ }
554
+ throw std::runtime_error("Invalid prop value for SkPaint::Cap received");
555
+ }
556
+
557
+ template <>
558
+ SkPath1DPathEffect::Style getPropertyValue(jsi::Runtime &runtime,
559
+ const jsi::Value &val) {
560
+ if (val.isString()) {
561
+ auto value = val.asString(runtime).utf8(runtime);
562
+ if (value == "translate") {
563
+ return SkPath1DPathEffect::Style::kTranslate_Style;
564
+ } else if (value == "rotate") {
565
+ return SkPath1DPathEffect::Style::kRotate_Style;
566
+ } else if (value == "morph") {
567
+ return SkPath1DPathEffect::Style::kMorph_Style;
568
+ }
569
+ }
570
+ throw std::runtime_error("Invalid prop value for Path1DEffectStyle received");
571
+ }
572
+
573
+ template <>
574
+ SkBlendMode getPropertyValue(jsi::Runtime &runtime, const jsi::Value &val) {
575
+ if (val.isString()) {
576
+ auto value = val.asString(runtime).utf8(runtime);
577
+ if (value == "clear") {
578
+ return SkBlendMode::kClear;
579
+ } else if (value == "src") {
580
+ return SkBlendMode::kSrc;
581
+ } else if (value == "dst") {
582
+ return SkBlendMode::kDst;
583
+ } else if (value == "srcOver") {
584
+ return SkBlendMode::kSrcOver;
585
+ } else if (value == "dstOver") {
586
+ return SkBlendMode::kDstOver;
587
+ } else if (value == "srcIn") {
588
+ return SkBlendMode::kSrcIn;
589
+ } else if (value == "dstIn") {
590
+ return SkBlendMode::kDstIn;
591
+ } else if (value == "srcOut") {
592
+ return SkBlendMode::kSrcOut;
593
+ } else if (value == "dstOut") {
594
+ return SkBlendMode::kDstOut;
595
+ } else if (value == "srcATop") {
596
+ return SkBlendMode::kSrcATop;
597
+ } else if (value == "dstATop") {
598
+ return SkBlendMode::kDstATop;
599
+ } else if (value == "xor") {
600
+ return SkBlendMode::kXor;
601
+ } else if (value == "plus") {
602
+ return SkBlendMode::kPlus;
603
+ } else if (value == "modulate") {
604
+ return SkBlendMode::kModulate;
605
+ } else if (value == "screen") {
606
+ return SkBlendMode::kScreen;
607
+ } else if (value == "overlay") {
608
+ return SkBlendMode::kOverlay;
609
+ } else if (value == "darken") {
610
+ return SkBlendMode::kDarken;
611
+ } else if (value == "lighten") {
612
+ return SkBlendMode::kLighten;
613
+ } else if (value == "colorDodge") {
614
+ return SkBlendMode::kColorDodge;
615
+ } else if (value == "colorBurn") {
616
+ return SkBlendMode::kColorBurn;
617
+ } else if (value == "hardLight") {
618
+ return SkBlendMode::kHardLight;
619
+ } else if (value == "softLight") {
620
+ return SkBlendMode::kSoftLight;
621
+ } else if (value == "difference") {
622
+ return SkBlendMode::kDifference;
623
+ } else if (value == "exclusion") {
624
+ return SkBlendMode::kExclusion;
625
+ } else if (value == "multiply") {
626
+ return SkBlendMode::kMultiply;
627
+ } else if (value == "hue") {
628
+ return SkBlendMode::kHue;
629
+ } else if (value == "saturation") {
630
+ return SkBlendMode::kSaturation;
631
+ } else if (value == "color") {
632
+ return SkBlendMode::kColor;
633
+ } else if (value == "luminosity") {
634
+ return SkBlendMode::kLuminosity;
635
+ }
636
+ }
637
+ throw std::runtime_error("Invalid prop value for SkBlendMode received");
638
+ }
639
+
640
+ using ClipDef = std::variant<SkPath, SkRRect, SkRect, std::string>;
641
+ using Layer = std::variant<SkPaint, bool>;
642
+
643
+ template <>
644
+ Uniforms getPropertyValue(jsi::Runtime &runtime, const jsi::Value &value) {
645
+ if (value.isObject()) {
646
+ Uniforms result;
647
+ auto obj = value.asObject(runtime);
648
+ auto names = obj.getPropertyNames(runtime);
649
+
650
+ for (size_t i = 0; i < names.length(runtime); i++) {
651
+ std::string propName =
652
+ names.getValueAtIndex(runtime, i).toString(runtime).utf8(runtime);
653
+ jsi::Value propValue = obj.getProperty(runtime, propName.c_str());
654
+
655
+ if (propValue.isNumber()) {
656
+ result[propName] =
657
+ std::vector<float>{static_cast<float>(propValue.asNumber())};
658
+ } else if (propValue.isObject() &&
659
+ propValue.asObject(runtime).isArray(runtime)) {
660
+ result[propName] =
661
+ processArray(runtime, propValue.asObject(runtime).asArray(runtime));
662
+ } else if (propValue.isObject() && isJSPoint(runtime, propValue)) {
663
+ result[propName] = {static_cast<float>(propValue.asObject(runtime)
664
+ .getProperty(runtime, "x")
665
+ .asNumber()),
666
+ static_cast<float>(propValue.asObject(runtime)
667
+ .getProperty(runtime, "y")
668
+ .asNumber())};
669
+ } else if (propValue.isObject() && isIndexable(runtime, propValue)) {
670
+ auto indexableObj = propValue.asObject(runtime);
671
+ std::vector<float> values;
672
+ values.reserve(4);
673
+ for (int i = 0; i < 4; i++) {
674
+ if (indexableObj.hasProperty(runtime, std::to_string(i).c_str())) {
675
+ values.push_back(static_cast<float>(
676
+ indexableObj.getProperty(runtime, std::to_string(i).c_str())
677
+ .asNumber()));
678
+ }
679
+ }
680
+ result[propName] = values;
681
+ }
682
+ }
683
+ return result;
684
+ }
685
+
686
+ throw std::runtime_error("Invalid prop value for Uniforms received");
687
+ }
688
+
689
+ template <>
690
+ SkBlurStyle getPropertyValue(jsi::Runtime &runtime, const jsi::Value &value) {
691
+ if (value.isString()) {
692
+ auto valueStr = value.asString(runtime).utf8(runtime);
693
+ if (valueStr == "normal") {
694
+ return SkBlurStyle::kNormal_SkBlurStyle;
695
+ } else if (valueStr == "solid") {
696
+ return SkBlurStyle::kSolid_SkBlurStyle;
697
+ } else if (valueStr == "outer") {
698
+ return SkBlurStyle::kOuter_SkBlurStyle;
699
+ } else if (valueStr == "inner") {
700
+ return SkBlurStyle::kInner_SkBlurStyle;
701
+ }
702
+ }
703
+ throw std::runtime_error("Invalid prop value for SkBlurStyle received");
704
+ }
705
+
706
+ template <>
707
+ SkPathFillType getPropertyValue(jsi::Runtime &runtime,
708
+ const jsi::Value &value) {
709
+ if (value.isString()) {
710
+ auto valueStr = value.asString(runtime).utf8(runtime);
711
+ if (valueStr == "winding") {
712
+ return SkPathFillType::kWinding;
713
+ } else if (valueStr == "evenOdd") {
714
+ return SkPathFillType::kEvenOdd;
715
+ } else if (valueStr == "inverseWinding") {
716
+ return SkPathFillType::kInverseWinding;
717
+ } else if (valueStr == "inverseEvenOdd") {
718
+ return SkPathFillType::kInverseEvenOdd;
719
+ }
720
+ }
721
+ throw std::runtime_error("Invalid prop value for SkPathFillType received");
722
+ }
723
+
724
+ struct StrokeOpts {
725
+ std::optional<float> width;
726
+ std::optional<float> miter_limit;
727
+ std::optional<float> precision;
728
+ std::optional<SkPaint::Join> join;
729
+ std::optional<SkPaint::Cap> cap;
730
+ };
731
+
732
+ template <>
733
+ StrokeOpts getPropertyValue(jsi::Runtime &runtime, const jsi::Value &value) {
734
+ if (value.isObject()) {
735
+ StrokeOpts opts;
736
+ auto object = value.asObject(runtime);
737
+ if (object.hasProperty(runtime, "width")) {
738
+ opts.width = object.getProperty(runtime, "width").asNumber();
739
+ }
740
+ if (object.hasProperty(runtime, "miterLimit")) {
741
+ opts.miter_limit = object.getProperty(runtime, "miterLimit").asNumber();
742
+ }
743
+ if (object.hasProperty(runtime, "precision")) {
744
+ opts.precision = object.getProperty(runtime, "precision").asNumber();
745
+ }
746
+ if (object.hasProperty(runtime, "join")) {
747
+ opts.join = getPropertyValue<SkPaint::Join>(
748
+ runtime, object.getProperty(runtime, "join"));
749
+ }
750
+ if (object.hasProperty(runtime, "cap")) {
751
+ opts.cap = getPropertyValue<SkPaint::Cap>(
752
+ runtime, object.getProperty(runtime, "cap"));
753
+ }
754
+ return opts;
755
+ }
756
+ throw std::runtime_error("Invalid prop value for StrokeOpts received");
757
+ }
758
+
759
+ template <>
760
+ SkRRect getPropertyValue(jsi::Runtime &runtime, const jsi::Value &value) {
761
+ if (value.isObject()) {
762
+ auto rect = processRRect(runtime, value);
763
+ if (!rect) {
764
+ throw std::runtime_error("Invalid prop value for SkRRect received");
765
+ }
766
+ return SkRRect(*rect);
767
+ }
768
+ throw std::runtime_error("Invalid prop value for SkRRect received");
769
+ }
770
+
771
+ template <>
772
+ SkRect getPropertyValue(jsi::Runtime &runtime, const jsi::Value &value) {
773
+ if (value.isObject()) {
774
+ auto rect = processRect(runtime, value);
775
+ if (!rect) {
776
+ throw std::runtime_error("Invalid prop value for SkRect received");
777
+ }
778
+ return SkRect(*rect);
779
+ }
780
+ throw std::runtime_error("Invalid prop value for SkRect received");
781
+ }
782
+
783
+ template <>
784
+ std::variant<SkRect, SkRRect> getPropertyValue(jsi::Runtime &runtime,
785
+ const jsi::Value &value) {
786
+ if (value.isObject()) {
787
+ auto rect = processRect(runtime, value);
788
+ if (rect) {
789
+ return SkRect(*rect);
790
+ }
791
+ auto rrect = processRRect(runtime, value);
792
+ if (rrect) {
793
+ return SkRRect(*rrect);
794
+ }
795
+ }
796
+ throw std::runtime_error("Invalid prop value for SkRect received");
797
+ }
798
+
799
+ template <>
800
+ SkPath getPropertyValue(jsi::Runtime &runtime, const jsi::Value &value) {
801
+ auto path = processPath(runtime, value);
802
+ if (!path) {
803
+ throw std::runtime_error("Invalid prop value for SkPath received");
804
+ }
805
+ return SkPath(*path);
806
+ }
807
+
808
+ template <>
809
+ ClipDef getPropertyValue(jsi::Runtime &runtime, const jsi::Value &value) {
810
+ auto path = processPath(runtime, value);
811
+ if (path) {
812
+ ClipDef def = SkPath(*path);
813
+ return def;
814
+ }
815
+ auto rect = processRect(runtime, value);
816
+ if (rect) {
817
+ ClipDef def = SkRect(*rect);
818
+ return def;
819
+ }
820
+ auto rrect = processRRect(runtime, value);
821
+ if (rrect) {
822
+ ClipDef def = SkRRect(*rrect);
823
+ return def;
824
+ }
825
+ throw std::runtime_error("Invalid prop value for ClipDef received");
826
+ }
827
+
828
+ template <>
829
+ Layer getPropertyValue(jsi::Runtime &runtime, const jsi::Value &value) {
830
+ if (value.isBool()) {
831
+ Layer layer = value.asBool();
832
+ return layer;
833
+ } else if (value.isObject() &&
834
+ value.asObject(runtime).isHostObject(runtime)) {
835
+ auto paint =
836
+ value.asObject(runtime).asHostObject<JsiSkPaint>(runtime)->getObject();
837
+ Layer layer = SkPaint(*paint);
838
+ return layer;
839
+ }
840
+ throw std::runtime_error("Invalid prop value for Layer received");
841
+ }
842
+
843
+ template <>
844
+ Patch getPropertyValue(jsi::Runtime &runtime, const jsi::Value &value) {
845
+ if (value.isObject() && value.asObject(runtime).isArray(runtime)) {
846
+ auto array = value.asObject(runtime).asArray(runtime);
847
+ if (array.size(runtime) != 4) {
848
+ throw std::runtime_error("Patch must contain exactly 4 bezier handles");
849
+ }
850
+
851
+ // Patch requires points in the following order:
852
+ // M tl
853
+ // C c1 c2 br
854
+ // C c1 c2 bl
855
+ // C c1 c2 tl (the redundant point in the last command is removed)
856
+
857
+ Patch result;
858
+
859
+ result[0] = processPoint(runtime, array.getValueAtIndex(runtime, 0)
860
+ .asObject(runtime)
861
+ .getProperty(runtime, "pos"));
862
+ result[1] = processPoint(runtime, array.getValueAtIndex(runtime, 0)
863
+ .asObject(runtime)
864
+ .getProperty(runtime, "c2"));
865
+ result[2] = processPoint(runtime, array.getValueAtIndex(runtime, 1)
866
+ .asObject(runtime)
867
+ .getProperty(runtime, "c1"));
868
+ result[3] = processPoint(runtime, array.getValueAtIndex(runtime, 1)
869
+ .asObject(runtime)
870
+ .getProperty(runtime, "pos"));
871
+ result[4] = processPoint(runtime, array.getValueAtIndex(runtime, 1)
872
+ .asObject(runtime)
873
+ .getProperty(runtime, "c2"));
874
+ result[5] = processPoint(runtime, array.getValueAtIndex(runtime, 2)
875
+ .asObject(runtime)
876
+ .getProperty(runtime, "c1"));
877
+ result[6] = processPoint(runtime, array.getValueAtIndex(runtime, 2)
878
+ .asObject(runtime)
879
+ .getProperty(runtime, "pos"));
880
+ result[7] = processPoint(runtime, array.getValueAtIndex(runtime, 2)
881
+ .asObject(runtime)
882
+ .getProperty(runtime, "c2"));
883
+ result[8] = processPoint(runtime, array.getValueAtIndex(runtime, 3)
884
+ .asObject(runtime)
885
+ .getProperty(runtime, "c1"));
886
+ result[9] = processPoint(runtime, array.getValueAtIndex(runtime, 3)
887
+ .asObject(runtime)
888
+ .getProperty(runtime, "pos"));
889
+ result[10] = processPoint(runtime, array.getValueAtIndex(runtime, 3)
890
+ .asObject(runtime)
891
+ .getProperty(runtime, "c2"));
892
+ result[11] = processPoint(runtime, array.getValueAtIndex(runtime, 0)
893
+ .asObject(runtime)
894
+ .getProperty(runtime, "c1"));
895
+
896
+ return result;
897
+ }
898
+ throw std::runtime_error("Invalid prop value for Patch received");
899
+ }
900
+
901
+ template <>
902
+ std::vector<SkRSXform> getPropertyValue(jsi::Runtime &runtime,
903
+ const jsi::Value &value) {
904
+ std::vector<SkRSXform> result;
905
+ if (value.isObject() && value.asObject(runtime).isArray(runtime)) {
906
+ auto array = value.asObject(runtime).asArray(runtime);
907
+ size_t size = array.size(runtime);
908
+ result.reserve(size);
909
+
910
+ for (size_t i = 0; i < size; i++) {
911
+ result.push_back(getPropertyValue<SkRSXform>(
912
+ runtime, array.getValueAtIndex(runtime, i)));
913
+ }
914
+ }
915
+ return result;
916
+ }
917
+
918
+ template <>
919
+ std::vector<SkPoint> getPropertyValue(jsi::Runtime &runtime,
920
+ const jsi::Value &value) {
921
+ std::vector<SkPoint> result;
922
+ if (value.isObject() && value.asObject(runtime).isArray(runtime)) {
923
+ auto array = value.asObject(runtime).asArray(runtime);
924
+ size_t size = array.size(runtime);
925
+ result.reserve(size);
926
+
927
+ for (size_t i = 0; i < size; i++) {
928
+ auto point = processPoint(runtime, array.getValueAtIndex(runtime, i));
929
+ result.push_back(point);
930
+ }
931
+ }
932
+ return result;
933
+ }
934
+
935
+ template <>
936
+ std::vector<SkRect> getPropertyValue(jsi::Runtime &runtime,
937
+ const jsi::Value &value) {
938
+ std::vector<SkRect> result;
939
+ if (value.isObject() && value.asObject(runtime).isArray(runtime)) {
940
+ auto array = value.asObject(runtime).asArray(runtime);
941
+ size_t size = array.size(runtime);
942
+ result.reserve(size);
943
+
944
+ for (size_t i = 0; i < size; i++) {
945
+ auto rect = processRect(runtime, array.getValueAtIndex(runtime, i));
946
+ if (rect) {
947
+ result.push_back(*rect);
948
+ } else {
949
+ throw std::runtime_error("Invalid rect in array at index " +
950
+ std::to_string(i));
951
+ }
952
+ }
953
+ }
954
+ return result;
955
+ }
956
+
957
+ template <>
958
+ std::vector<float> getPropertyValue(jsi::Runtime &runtime,
959
+ const jsi::Value &value) {
960
+ std::vector<float> result;
961
+
962
+ if (value.isNumber()) {
963
+ // If single number, create a vector with one element
964
+ result.push_back(static_cast<float>(value.asNumber()));
965
+ } else if (value.isObject()) {
966
+ auto obj = value.asObject(runtime);
967
+ if (obj.isArray(runtime)) {
968
+ auto array = obj.asArray(runtime);
969
+ size_t size = array.size(runtime);
970
+ result.reserve(size);
971
+
972
+ for (size_t i = 0; i < size; i++) {
973
+ jsi::Value element = array.getValueAtIndex(runtime, i);
974
+ if (element.isNumber()) {
975
+ result.push_back(static_cast<float>(element.asNumber()));
976
+ } else {
977
+ throw std::runtime_error("Array elements must be numbers");
978
+ }
979
+ }
980
+ } else {
981
+ throw std::runtime_error("Expected array or number for vector<float>");
982
+ }
983
+ } else {
984
+ throw std::runtime_error("Invalid value type for vector<float>");
985
+ }
986
+
987
+ return result;
988
+ }
989
+
990
+ template <>
991
+ std::vector<uint16_t> getPropertyValue(jsi::Runtime &runtime,
992
+ const jsi::Value &value) {
993
+ std::vector<uint16_t> result;
994
+
995
+ if (value.isNumber()) {
996
+ // If single number, create a vector with one element
997
+ result.push_back(static_cast<float>(value.asNumber()));
998
+ } else if (value.isObject()) {
999
+ auto obj = value.asObject(runtime);
1000
+ if (obj.isArray(runtime)) {
1001
+ auto array = obj.asArray(runtime);
1002
+ size_t size = array.size(runtime);
1003
+ result.reserve(size);
1004
+
1005
+ for (size_t i = 0; i < size; i++) {
1006
+ jsi::Value element = array.getValueAtIndex(runtime, i);
1007
+ if (element.isNumber()) {
1008
+ result.push_back(static_cast<uint16_t>(element.asNumber()));
1009
+ } else {
1010
+ throw std::runtime_error("Array elements must be numbers");
1011
+ }
1012
+ }
1013
+ } else {
1014
+ throw std::runtime_error("Expected array or number for vector<uint16_t>");
1015
+ }
1016
+ } else {
1017
+ throw std::runtime_error("Invalid value type for vector<uint16_t>");
1018
+ }
1019
+
1020
+ return result;
1021
+ }
1022
+
1023
+ template <>
1024
+ bool getPropertyValue(jsi::Runtime &runtime, const jsi::Value &value) {
1025
+ if (value.isBool()) {
1026
+ return value.asBool();
1027
+ }
1028
+ throw std::runtime_error("Invalid prop value for bool received");
1029
+ }
1030
+
1031
+ //
1032
+ template <typename T>
1033
+ std::optional<T> makeOptionalPropertyValue(jsi::Runtime &runtime,
1034
+ const jsi::Value &value) {
1035
+ if (value.isNull() || value.isUndefined()) {
1036
+ return std::nullopt;
1037
+ }
1038
+ try {
1039
+ return getPropertyValue<T>(runtime, value);
1040
+ } catch (const std::runtime_error &) {
1041
+ return std::nullopt;
1042
+ }
1043
+ }
1044
+
1045
+ template <>
1046
+ std::optional<float> getPropertyValue(jsi::Runtime &runtime,
1047
+ const jsi::Value &value) {
1048
+ return makeOptionalPropertyValue<float>(runtime, value);
1049
+ }
1050
+
1051
+ template <>
1052
+ std::optional<SkPoint> getPropertyValue(jsi::Runtime &runtime,
1053
+ const jsi::Value &value) {
1054
+ return makeOptionalPropertyValue<SkPoint>(runtime, value);
1055
+ }
1056
+
1057
+ template <>
1058
+ std::optional<SkColor> getPropertyValue(jsi::Runtime &runtime,
1059
+ const jsi::Value &value) {
1060
+ return makeOptionalPropertyValue<SkColor>(runtime, value);
1061
+ }
1062
+
1063
+ template <>
1064
+ std::optional<SkBlendMode> getPropertyValue(jsi::Runtime &runtime,
1065
+ const jsi::Value &value) {
1066
+ return makeOptionalPropertyValue<SkBlendMode>(runtime, value);
1067
+ }
1068
+
1069
+ template <>
1070
+ std::optional<SkMatrix> getPropertyValue(jsi::Runtime &runtime,
1071
+ const jsi::Value &value) {
1072
+ return makeOptionalPropertyValue<SkMatrix>(runtime, value);
1073
+ }
1074
+
1075
+ template <>
1076
+ std::optional<SkM44> getPropertyValue(jsi::Runtime &runtime,
1077
+ const jsi::Value &value) {
1078
+ return makeOptionalPropertyValue<SkM44>(runtime, value);
1079
+ }
1080
+
1081
+ template <>
1082
+ std::optional<bool> getPropertyValue(jsi::Runtime &runtime,
1083
+ const jsi::Value &value) {
1084
+ return makeOptionalPropertyValue<bool>(runtime, value);
1085
+ }
1086
+
1087
+ template <>
1088
+ std::optional<ClipDef> getPropertyValue(jsi::Runtime &runtime,
1089
+ const jsi::Value &value) {
1090
+ return makeOptionalPropertyValue<ClipDef>(runtime, value);
1091
+ }
1092
+
1093
+ template <>
1094
+ std::optional<Layer> getPropertyValue(jsi::Runtime &runtime,
1095
+ const jsi::Value &value) {
1096
+ return makeOptionalPropertyValue<Layer>(runtime, value);
1097
+ }
1098
+
1099
+ template <>
1100
+ std::optional<SkFont> getPropertyValue(jsi::Runtime &runtime,
1101
+ const jsi::Value &value) {
1102
+ return makeOptionalPropertyValue<SkFont>(runtime, value);
1103
+ }
1104
+
1105
+ template <>
1106
+ std::optional<SkPaint::Style> getPropertyValue(jsi::Runtime &runtime,
1107
+ const jsi::Value &value) {
1108
+ return makeOptionalPropertyValue<SkPaint::Style>(runtime, value);
1109
+ }
1110
+
1111
+ template <>
1112
+ std::optional<SkPaint::Join> getPropertyValue(jsi::Runtime &runtime,
1113
+ const jsi::Value &value) {
1114
+ return makeOptionalPropertyValue<SkPaint::Join>(runtime, value);
1115
+ }
1116
+
1117
+ template <>
1118
+ std::optional<SkPaint::Cap> getPropertyValue(jsi::Runtime &runtime,
1119
+ const jsi::Value &value) {
1120
+ return makeOptionalPropertyValue<SkPaint::Cap>(runtime, value);
1121
+ }
1122
+
1123
+ template <>
1124
+ std::optional<SkRect> getPropertyValue(jsi::Runtime &runtime,
1125
+ const jsi::Value &value) {
1126
+ return makeOptionalPropertyValue<SkRect>(runtime, value);
1127
+ }
1128
+
1129
+ template <>
1130
+ std::optional<sk_sp<SkImage>> getPropertyValue(jsi::Runtime &runtime,
1131
+ const jsi::Value &value) {
1132
+ return makeOptionalPropertyValue<sk_sp<SkImage>>(runtime, value);
1133
+ }
1134
+
1135
+ template <>
1136
+ std::optional<SkSamplingOptions> getPropertyValue(jsi::Runtime &runtime,
1137
+ const jsi::Value &value) {
1138
+ return makeOptionalPropertyValue<SkSamplingOptions>(runtime, value);
1139
+ }
1140
+
1141
+ template <>
1142
+ std::optional<StrokeOpts> getPropertyValue(jsi::Runtime &runtime,
1143
+ const jsi::Value &value) {
1144
+ return makeOptionalPropertyValue<StrokeOpts>(runtime, value);
1145
+ }
1146
+
1147
+ template <>
1148
+ std::optional<std::vector<SkColor>> getPropertyValue(jsi::Runtime &runtime,
1149
+ const jsi::Value &value) {
1150
+ return makeOptionalPropertyValue<std::vector<SkColor>>(runtime, value);
1151
+ }
1152
+
1153
+ template <>
1154
+ std::optional<std::vector<float>> getPropertyValue(jsi::Runtime &runtime,
1155
+ const jsi::Value &value) {
1156
+ return makeOptionalPropertyValue<std::vector<float>>(runtime, value);
1157
+ }
1158
+
1159
+ template <>
1160
+ std::optional<SkTileMode> getPropertyValue(jsi::Runtime &runtime,
1161
+ const jsi::Value &value) {
1162
+ return makeOptionalPropertyValue<SkTileMode>(runtime, value);
1163
+ }
1164
+
1165
+ template <>
1166
+ std::optional<SkPathFillType> getPropertyValue(jsi::Runtime &runtime,
1167
+ const jsi::Value &value) {
1168
+ return makeOptionalPropertyValue<SkPathFillType>(runtime, value);
1169
+ }
1170
+
1171
+ template <>
1172
+ std::optional<SkColorChannel> getPropertyValue(jsi::Runtime &runtime,
1173
+ const jsi::Value &value) {
1174
+ return makeOptionalPropertyValue<SkColorChannel>(runtime, value);
1175
+ }
1176
+
1177
+ template <>
1178
+ std::optional<Uniforms> getPropertyValue(jsi::Runtime &runtime,
1179
+ const jsi::Value &value) {
1180
+ return makeOptionalPropertyValue<Uniforms>(runtime, value);
1181
+ }
1182
+
1183
+ template <>
1184
+ std::optional<Radius> getPropertyValue(jsi::Runtime &runtime,
1185
+ const jsi::Value &value) {
1186
+ return makeOptionalPropertyValue<Radius>(runtime, value);
1187
+ }
1188
+
1189
+ template <>
1190
+ std::optional<SkRRect> getPropertyValue(jsi::Runtime &runtime,
1191
+ const jsi::Value &value) {
1192
+ return makeOptionalPropertyValue<SkRRect>(runtime, value);
1193
+ }
1194
+
1195
+ template <>
1196
+ std::optional<SkPaint> getPropertyValue(jsi::Runtime &runtime,
1197
+ const jsi::Value &value) {
1198
+ return makeOptionalPropertyValue<SkPaint>(runtime, value);
1199
+ }
1200
+
1201
+ template <>
1202
+ std::optional<std::vector<SkPoint>> getPropertyValue(jsi::Runtime &runtime,
1203
+ const jsi::Value &value) {
1204
+ return makeOptionalPropertyValue<std::vector<SkPoint>>(runtime, value);
1205
+ }
1206
+
1207
+ template <>
1208
+ std::optional<std::vector<uint16_t>> getPropertyValue(jsi::Runtime &runtime,
1209
+ const jsi::Value &value) {
1210
+ return makeOptionalPropertyValue<std::vector<uint16_t>>(runtime, value);
1211
+ }
1212
+
1213
+ } // namespace RNSkia