@shopify/react-native-skia 1.10.2 → 1.11.1

Sign up to get free protection for your applications and to get access to all the features.
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