@shopify/react-native-skia 1.10.2 → 1.11.0
Sign up to get free protection for your applications and to get access to all the features.
- package/cpp/api/JsiSkApi.h +3 -0
- package/cpp/api/recorder/ColorFilters.h +133 -0
- package/cpp/api/recorder/Command.h +58 -0
- package/cpp/api/recorder/Convertor.h +1212 -0
- package/cpp/api/recorder/DataTypes.h +234 -0
- package/cpp/api/recorder/DrawingCtx.h +187 -0
- package/cpp/api/recorder/Drawings.h +949 -0
- package/cpp/api/recorder/Image.h +108 -0
- package/cpp/api/recorder/ImageFilters.h +292 -0
- package/cpp/api/recorder/JsiRecorder.h +314 -0
- package/cpp/api/recorder/Paint.h +191 -0
- package/cpp/api/recorder/PathEffects.h +194 -0
- package/cpp/api/recorder/RNRecorder.h +635 -0
- package/cpp/api/recorder/Shaders.h +406 -0
- package/cpp/rnskia/dom/nodes/JsiAtlasNode.h +3 -2
- package/cpp/rnskia/dom/nodes/JsiImageNode.h +3 -2
- package/ios/RNSkia-iOS/SkiaCVPixelBufferUtils.mm +4 -8
- package/jestSetup.js +8 -0
- package/jestSetup.mjs +8 -0
- package/lib/commonjs/renderer/components/image/Image.d.ts +1 -1
- package/lib/commonjs/renderer/components/image/Image.js +8 -2
- package/lib/commonjs/renderer/components/image/Image.js.map +1 -1
- package/lib/commonjs/skia/types/Recorder.d.ts +52 -0
- package/lib/commonjs/skia/types/Recorder.js +6 -0
- package/lib/commonjs/skia/types/Recorder.js.map +1 -0
- package/lib/commonjs/skia/types/Skia.d.ts +2 -0
- package/lib/commonjs/skia/types/Skia.js.map +1 -1
- package/lib/commonjs/skia/types/index.d.ts +1 -0
- package/lib/commonjs/skia/types/index.js +11 -0
- package/lib/commonjs/skia/types/index.js.map +1 -1
- package/lib/commonjs/skia/web/JsiSkia.js +3 -0
- package/lib/commonjs/skia/web/JsiSkia.js.map +1 -1
- package/lib/commonjs/sksg/Container.d.ts +6 -1
- package/lib/commonjs/sksg/Container.js +59 -2
- package/lib/commonjs/sksg/Container.js.map +1 -1
- package/lib/commonjs/sksg/Recorder/DrawingContext.js +1 -0
- package/lib/commonjs/sksg/Recorder/DrawingContext.js.map +1 -1
- package/lib/commonjs/sksg/Recorder/ReanimatedRecorder.d.ts +53 -0
- package/lib/commonjs/sksg/Recorder/ReanimatedRecorder.js +189 -0
- package/lib/commonjs/sksg/Recorder/ReanimatedRecorder.js.map +1 -0
- package/lib/commonjs/sksg/Recorder/Recorder.d.ts +2 -2
- package/lib/commonjs/sksg/Recorder/Recorder.js.map +1 -1
- package/lib/commonjs/sksg/Recorder/Visitor.d.ts +2 -2
- package/lib/commonjs/sksg/Recorder/Visitor.js +2 -2
- package/lib/commonjs/sksg/Recorder/Visitor.js.map +1 -1
- package/lib/module/renderer/components/image/Image.d.ts +1 -1
- package/lib/module/renderer/components/image/Image.js +8 -2
- package/lib/module/renderer/components/image/Image.js.map +1 -1
- package/lib/module/skia/types/Recorder.d.ts +52 -0
- package/lib/module/skia/types/Recorder.js +2 -0
- package/lib/module/skia/types/Recorder.js.map +1 -0
- package/lib/module/skia/types/Skia.d.ts +2 -0
- package/lib/module/skia/types/Skia.js.map +1 -1
- package/lib/module/skia/types/index.d.ts +1 -0
- package/lib/module/skia/types/index.js +1 -0
- package/lib/module/skia/types/index.js.map +1 -1
- package/lib/module/skia/web/JsiSkia.js +3 -0
- package/lib/module/skia/web/JsiSkia.js.map +1 -1
- package/lib/module/sksg/Container.d.ts +6 -1
- package/lib/module/sksg/Container.js +59 -2
- package/lib/module/sksg/Container.js.map +1 -1
- package/lib/module/sksg/Recorder/DrawingContext.js +1 -0
- package/lib/module/sksg/Recorder/DrawingContext.js.map +1 -1
- package/lib/module/sksg/Recorder/ReanimatedRecorder.d.ts +53 -0
- package/lib/module/sksg/Recorder/ReanimatedRecorder.js +182 -0
- package/lib/module/sksg/Recorder/ReanimatedRecorder.js.map +1 -0
- package/lib/module/sksg/Recorder/Recorder.d.ts +2 -2
- package/lib/module/sksg/Recorder/Recorder.js.map +1 -1
- package/lib/module/sksg/Recorder/Visitor.d.ts +2 -2
- package/lib/module/sksg/Recorder/Visitor.js +2 -2
- package/lib/module/sksg/Recorder/Visitor.js.map +1 -1
- package/lib/typescript/lib/commonjs/renderer/components/image/Image.d.ts +4 -1
- package/lib/typescript/lib/commonjs/skia/types/Recorder.d.ts +1 -0
- package/lib/typescript/lib/commonjs/skia/web/JsiSkia.d.ts +1 -0
- package/lib/typescript/lib/commonjs/sksg/Container.d.ts +5 -1
- package/lib/typescript/lib/commonjs/sksg/Reconciler.d.ts +6 -0
- package/lib/typescript/lib/commonjs/sksg/Recorder/ReanimatedRecorder.d.ts +47 -0
- package/lib/typescript/lib/module/mock/index.d.ts +4 -1
- package/lib/typescript/lib/module/renderer/components/image/Image.d.ts +4 -1
- package/lib/typescript/lib/module/skia/Skia.web.d.ts +1 -0
- package/lib/typescript/lib/module/skia/types/Recorder.d.ts +1 -0
- package/lib/typescript/lib/module/skia/types/index.d.ts +1 -0
- package/lib/typescript/lib/module/skia/web/JsiSkia.d.ts +1 -0
- package/lib/typescript/lib/module/sksg/Container.d.ts +5 -1
- package/lib/typescript/lib/module/sksg/Reconciler.d.ts +6 -0
- package/lib/typescript/lib/module/sksg/Recorder/ReanimatedRecorder.d.ts +46 -0
- package/lib/typescript/src/renderer/components/image/Image.d.ts +1 -1
- package/lib/typescript/src/skia/types/Recorder.d.ts +52 -0
- package/lib/typescript/src/skia/types/Skia.d.ts +2 -0
- package/lib/typescript/src/skia/types/index.d.ts +1 -0
- package/lib/typescript/src/sksg/Container.d.ts +6 -1
- package/lib/typescript/src/sksg/Recorder/ReanimatedRecorder.d.ts +53 -0
- package/lib/typescript/src/sksg/Recorder/Recorder.d.ts +2 -2
- package/lib/typescript/src/sksg/Recorder/Visitor.d.ts +2 -2
- package/package.json +3 -2
- package/src/renderer/components/image/Image.tsx +2 -2
- package/src/skia/types/Recorder.ts +91 -0
- package/src/skia/types/Skia.ts +2 -0
- package/src/skia/types/index.ts +1 -0
- package/src/skia/web/JsiSkia.ts +3 -0
- package/src/sksg/Container.ts +63 -4
- package/src/sksg/Recorder/DrawingContext.ts +1 -0
- package/src/sksg/Recorder/ReanimatedRecorder.ts +271 -0
- package/src/sksg/Recorder/Recorder.ts +2 -2
- package/src/sksg/Recorder/Visitor.ts +17 -12
@@ -0,0 +1,108 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
#include <string>
|
4
|
+
|
5
|
+
#include <include/core/SkMatrix.h>
|
6
|
+
#include <include/core/SkRect.h>
|
7
|
+
|
8
|
+
// TODO: to rename once the old reconciler is removed
|
9
|
+
namespace RNSkiaImage {
|
10
|
+
|
11
|
+
struct FitSizes {
|
12
|
+
SkSize src;
|
13
|
+
SkSize dst;
|
14
|
+
};
|
15
|
+
|
16
|
+
struct FitRects {
|
17
|
+
SkRect src;
|
18
|
+
SkRect dst;
|
19
|
+
};
|
20
|
+
|
21
|
+
SkRect inscribe(SkSize size, SkRect rect) {
|
22
|
+
auto halfWidthDelta = (rect.width() - size.width()) / 2.0;
|
23
|
+
auto halfHeightDelta = (rect.height() - size.height()) / 2.0;
|
24
|
+
return SkRect::MakeXYWH(rect.x() + halfWidthDelta, rect.y() + halfHeightDelta,
|
25
|
+
size.width(), size.height());
|
26
|
+
}
|
27
|
+
|
28
|
+
SkMatrix rect2rect(SkRect src, SkRect dst) {
|
29
|
+
auto sx = dst.width() / src.width();
|
30
|
+
auto sy = dst.height() / src.height();
|
31
|
+
auto tx = dst.x() - src.x() * sx;
|
32
|
+
auto ty = dst.y() - src.y() * sy;
|
33
|
+
SkMatrix m3;
|
34
|
+
m3.preTranslate(tx, ty);
|
35
|
+
m3.preScale(sx, sy);
|
36
|
+
return m3;
|
37
|
+
}
|
38
|
+
|
39
|
+
SkSize size(double width, double height) { return SkSize::Make(width, height); }
|
40
|
+
|
41
|
+
FitSizes applyBoxFit(const std::string fit, SkSize input, SkSize output) {
|
42
|
+
SkSize src = size(0, 0);
|
43
|
+
SkSize dst = size(0, 0);
|
44
|
+
|
45
|
+
if (input.height() <= 0.0 || input.width() <= 0.0 || output.height() <= 0.0 ||
|
46
|
+
output.width() <= 0.0) {
|
47
|
+
return {.src = src, .dst = dst};
|
48
|
+
}
|
49
|
+
|
50
|
+
if (fit == "fill") {
|
51
|
+
src = input;
|
52
|
+
dst = output;
|
53
|
+
} else if (fit == "contain") {
|
54
|
+
src = input;
|
55
|
+
if (output.width() / output.height() > src.width() / src.height()) {
|
56
|
+
dst =
|
57
|
+
size((src.width() * output.height()) / src.height(), output.height());
|
58
|
+
} else {
|
59
|
+
dst = size(output.width(), (src.height() * output.width()) / src.width());
|
60
|
+
}
|
61
|
+
} else if (fit == "cover") {
|
62
|
+
if (output.width() / output.height() > input.width() / input.height()) {
|
63
|
+
src = size(input.width(),
|
64
|
+
(input.width() * output.height()) / output.width());
|
65
|
+
} else {
|
66
|
+
src = size((input.height() * output.width()) / output.height(),
|
67
|
+
input.height());
|
68
|
+
}
|
69
|
+
dst = output;
|
70
|
+
} else if (fit == "fitWidth") {
|
71
|
+
src =
|
72
|
+
size(input.width(), (input.width() * output.height()) / output.width());
|
73
|
+
dst = size(output.width(), (src.height() * output.width()) / src.width());
|
74
|
+
} else if (fit == "fitHeight") {
|
75
|
+
src = size((input.height() * output.width()) / output.height(),
|
76
|
+
input.height());
|
77
|
+
dst = size((src.width() * output.height()) / src.height(), output.height());
|
78
|
+
} else if (fit == "none") {
|
79
|
+
src = size(std::min(input.width(), output.width()),
|
80
|
+
std::min(input.height(), output.height()));
|
81
|
+
dst = src;
|
82
|
+
} else if (fit == "scaleDown") {
|
83
|
+
src = input;
|
84
|
+
dst = input;
|
85
|
+
auto aspectRatio = input.width() / input.height();
|
86
|
+
if (dst.height() > output.height()) {
|
87
|
+
dst = size(output.height() * aspectRatio, output.height());
|
88
|
+
}
|
89
|
+
if (dst.width() > output.width()) {
|
90
|
+
dst = size(output.width(), output.width() / aspectRatio);
|
91
|
+
}
|
92
|
+
} else {
|
93
|
+
throw std::runtime_error("The value \"" + fit +
|
94
|
+
"\" is not a valid fit value.");
|
95
|
+
}
|
96
|
+
return {.src = src, .dst = dst};
|
97
|
+
}
|
98
|
+
|
99
|
+
FitRects fitRects(const std::string &fit, SkRect rect, SkRect rect2) {
|
100
|
+
auto sizes = applyBoxFit(fit, size(rect.width(), rect.height()),
|
101
|
+
size(rect2.width(), rect2.height()));
|
102
|
+
|
103
|
+
auto src = inscribe(sizes.src, rect);
|
104
|
+
auto dst = inscribe(sizes.dst, rect2);
|
105
|
+
|
106
|
+
return {.src = src, .dst = dst};
|
107
|
+
}
|
108
|
+
} // namespace RNSkiaImage
|
@@ -0,0 +1,292 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
#include <optional>
|
4
|
+
#include <string>
|
5
|
+
#include <variant>
|
6
|
+
|
7
|
+
#include "Command.h"
|
8
|
+
#include "Convertor.h"
|
9
|
+
#include "DrawingCtx.h"
|
10
|
+
|
11
|
+
namespace RNSkia {
|
12
|
+
|
13
|
+
struct BlurMaskFilterCmdProps {
|
14
|
+
float blur;
|
15
|
+
SkBlurStyle style;
|
16
|
+
bool respectCTM;
|
17
|
+
};
|
18
|
+
|
19
|
+
class BlurMaskFilterCmd : public Command {
|
20
|
+
private:
|
21
|
+
BlurMaskFilterCmdProps props;
|
22
|
+
|
23
|
+
public:
|
24
|
+
BlurMaskFilterCmd(jsi::Runtime &runtime, const jsi::Object &object,
|
25
|
+
Variables &variables)
|
26
|
+
: Command(CommandType::PushBlurMaskFilter, "skBlurMaskFilter") {
|
27
|
+
convertProperty(runtime, object, "blur", props.blur, variables);
|
28
|
+
convertProperty(runtime, object, "style", props.style, variables);
|
29
|
+
convertProperty(runtime, object, "respectCTM", props.respectCTM, variables);
|
30
|
+
}
|
31
|
+
|
32
|
+
void pushMaskFilter(DrawingCtx *ctx) {
|
33
|
+
auto [blur, style, respectCTM] = props;
|
34
|
+
auto maskFilter = SkMaskFilter::MakeBlur(style, blur, respectCTM);
|
35
|
+
ctx->getPaint().setMaskFilter(maskFilter);
|
36
|
+
}
|
37
|
+
};
|
38
|
+
|
39
|
+
struct BlurImageFilterProps {
|
40
|
+
Radius blur;
|
41
|
+
SkTileMode mode;
|
42
|
+
};
|
43
|
+
|
44
|
+
class BlurImageFilterCmd : public Command {
|
45
|
+
private:
|
46
|
+
BlurImageFilterProps props;
|
47
|
+
|
48
|
+
public:
|
49
|
+
BlurImageFilterCmd(jsi::Runtime &runtime, const jsi::Object &object,
|
50
|
+
Variables &variables)
|
51
|
+
: Command(CommandType::PushImageFilter, "skBlurImageFilter") {
|
52
|
+
convertProperty(runtime, object, "blur", props.blur, variables);
|
53
|
+
convertProperty(runtime, object, "mode", props.mode, variables);
|
54
|
+
}
|
55
|
+
|
56
|
+
void pushImageFilter(DrawingCtx *ctx) {
|
57
|
+
auto imgf =
|
58
|
+
SkImageFilters::Blur(props.blur.rX, props.blur.rY, props.mode, nullptr);
|
59
|
+
ctx->imageFilters.push_back(imgf);
|
60
|
+
}
|
61
|
+
};
|
62
|
+
|
63
|
+
struct OffsetImageFilterProps {
|
64
|
+
float x;
|
65
|
+
float y;
|
66
|
+
};
|
67
|
+
|
68
|
+
class OffsetImageFilterCmd : public Command {
|
69
|
+
private:
|
70
|
+
OffsetImageFilterProps props;
|
71
|
+
|
72
|
+
public:
|
73
|
+
OffsetImageFilterCmd(jsi::Runtime &runtime, const jsi::Object &object,
|
74
|
+
Variables &variables)
|
75
|
+
: Command(CommandType::PushImageFilter, "skOffsetImageFilter") {
|
76
|
+
convertProperty(runtime, object, "x", props.x, variables);
|
77
|
+
convertProperty(runtime, object, "y", props.y, variables);
|
78
|
+
}
|
79
|
+
|
80
|
+
void pushImageFilter(DrawingCtx *ctx) {
|
81
|
+
auto imgf = SkImageFilters::Offset(props.x, props.y, nullptr);
|
82
|
+
ctx->imageFilters.push_back(imgf);
|
83
|
+
}
|
84
|
+
};
|
85
|
+
|
86
|
+
struct DisplacementMapImageFilterProps {
|
87
|
+
SkColorChannel channelX;
|
88
|
+
SkColorChannel channelY;
|
89
|
+
float scale;
|
90
|
+
};
|
91
|
+
|
92
|
+
class DisplacementMapImageFilterCmd : public Command {
|
93
|
+
private:
|
94
|
+
DisplacementMapImageFilterProps props;
|
95
|
+
|
96
|
+
public:
|
97
|
+
DisplacementMapImageFilterCmd(jsi::Runtime &runtime,
|
98
|
+
const jsi::Object &object, Variables &variables)
|
99
|
+
: Command(CommandType::PushImageFilter, "skDisplacementMapImageFilter") {
|
100
|
+
convertProperty(runtime, object, "channelX", props.channelX, variables);
|
101
|
+
convertProperty(runtime, object, "channelY", props.channelY, variables);
|
102
|
+
convertProperty(runtime, object, "scale", props.scale, variables);
|
103
|
+
}
|
104
|
+
|
105
|
+
void pushImageFilter(DrawingCtx *ctx) {
|
106
|
+
auto shader = ctx->shaders.back();
|
107
|
+
ctx->shaders.pop_back();
|
108
|
+
auto map = SkImageFilters::Shader(shader, nullptr);
|
109
|
+
auto imgf = SkImageFilters::DisplacementMap(props.channelX, props.channelY,
|
110
|
+
props.scale, map, nullptr);
|
111
|
+
ctx->imageFilters.push_back(imgf);
|
112
|
+
}
|
113
|
+
};
|
114
|
+
|
115
|
+
struct DropShadowImageFilterProps {
|
116
|
+
float dx;
|
117
|
+
float dy;
|
118
|
+
float blur;
|
119
|
+
SkColor color;
|
120
|
+
std::optional<bool> inner;
|
121
|
+
std::optional<bool> shadowOnly;
|
122
|
+
};
|
123
|
+
|
124
|
+
class DropShadowImageFilterCmd : public Command {
|
125
|
+
private:
|
126
|
+
DropShadowImageFilterProps props;
|
127
|
+
|
128
|
+
sk_sp<SkImageFilter> MakeInnerShadow(bool shadowOnly, float dx, float dy,
|
129
|
+
float sigmaX, float sigmaY,
|
130
|
+
SkColor color,
|
131
|
+
sk_sp<SkImageFilter> input) {
|
132
|
+
auto sourceGraphic = SkImageFilters::ColorFilter(
|
133
|
+
SkColorFilters::Blend(SK_ColorBLACK, SkBlendMode::kDst), nullptr);
|
134
|
+
|
135
|
+
auto sourceAlpha = SkImageFilters::ColorFilter(
|
136
|
+
SkColorFilters::Blend(SK_ColorBLACK, SkBlendMode::kSrcIn), nullptr);
|
137
|
+
|
138
|
+
auto f1 = SkImageFilters::ColorFilter(
|
139
|
+
SkColorFilters::Blend(color, SkBlendMode::kSrcOut), nullptr);
|
140
|
+
|
141
|
+
auto f2 = SkImageFilters::Offset(dx, dy, f1);
|
142
|
+
auto f3 = SkImageFilters::Blur(sigmaX, sigmaY, SkTileMode::kDecal, f2);
|
143
|
+
auto f4 = SkImageFilters::Blend(SkBlendMode::kSrcIn, sourceAlpha, f3);
|
144
|
+
|
145
|
+
if (shadowOnly) {
|
146
|
+
return f4;
|
147
|
+
}
|
148
|
+
|
149
|
+
return SkImageFilters::Compose(
|
150
|
+
input, SkImageFilters::Blend(SkBlendMode::kSrcOver, sourceGraphic, f4));
|
151
|
+
}
|
152
|
+
|
153
|
+
public:
|
154
|
+
DropShadowImageFilterCmd(jsi::Runtime &runtime, const jsi::Object &object,
|
155
|
+
Variables &variables)
|
156
|
+
: Command(CommandType::PushImageFilter, "skDropShadowImageFilter") {
|
157
|
+
convertProperty(runtime, object, "dx", props.dx, variables);
|
158
|
+
convertProperty(runtime, object, "dy", props.dy, variables);
|
159
|
+
convertProperty(runtime, object, "blur", props.blur, variables);
|
160
|
+
convertProperty(runtime, object, "color", props.color, variables);
|
161
|
+
convertProperty(runtime, object, "inner", props.inner, variables);
|
162
|
+
convertProperty(runtime, object, "shadowOnly", props.shadowOnly, variables);
|
163
|
+
}
|
164
|
+
|
165
|
+
void pushImageFilter(DrawingCtx *ctx) {
|
166
|
+
auto shadowOnly = props.shadowOnly.value_or(false);
|
167
|
+
auto inner = props.inner.value_or(false);
|
168
|
+
|
169
|
+
sk_sp<SkImageFilter> imgf;
|
170
|
+
if (inner) {
|
171
|
+
imgf = MakeInnerShadow(shadowOnly, props.dx, props.dy, props.blur,
|
172
|
+
props.blur, props.color, nullptr);
|
173
|
+
} else {
|
174
|
+
if (shadowOnly) {
|
175
|
+
imgf = SkImageFilters::DropShadowOnly(props.dx, props.dy, props.blur,
|
176
|
+
props.blur, props.color, nullptr);
|
177
|
+
} else {
|
178
|
+
imgf = SkImageFilters::DropShadow(props.dx, props.dy, props.blur,
|
179
|
+
props.blur, props.color, nullptr);
|
180
|
+
}
|
181
|
+
}
|
182
|
+
ctx->imageFilters.push_back(imgf);
|
183
|
+
}
|
184
|
+
};
|
185
|
+
|
186
|
+
struct MorphologyImageFilterProps {
|
187
|
+
std::string op; // "erode" or "dilate"
|
188
|
+
Radius radius;
|
189
|
+
};
|
190
|
+
|
191
|
+
class MorphologyImageFilterCmd : public Command {
|
192
|
+
private:
|
193
|
+
MorphologyImageFilterProps props;
|
194
|
+
|
195
|
+
public:
|
196
|
+
MorphologyImageFilterCmd(jsi::Runtime &runtime, const jsi::Object &object,
|
197
|
+
Variables &variables)
|
198
|
+
: Command(CommandType::PushImageFilter, "skMorphologyImageFilter") {
|
199
|
+
convertProperty(runtime, object, "operator", props.op, variables);
|
200
|
+
convertProperty(runtime, object, "radius", props.radius, variables);
|
201
|
+
}
|
202
|
+
|
203
|
+
void pushImageFilter(DrawingCtx *ctx) {
|
204
|
+
if (props.op == "erode") {
|
205
|
+
auto imgf =
|
206
|
+
SkImageFilters::Erode(props.radius.rX, props.radius.rY, nullptr);
|
207
|
+
ctx->imageFilters.push_back(imgf);
|
208
|
+
} else {
|
209
|
+
auto imgf =
|
210
|
+
SkImageFilters::Dilate(props.radius.rX, props.radius.rY, nullptr);
|
211
|
+
ctx->imageFilters.push_back(imgf);
|
212
|
+
}
|
213
|
+
}
|
214
|
+
};
|
215
|
+
|
216
|
+
struct BlendImageFilterProps {
|
217
|
+
SkBlendMode mode;
|
218
|
+
};
|
219
|
+
|
220
|
+
class BlendImageFilterCmd : public Command {
|
221
|
+
private:
|
222
|
+
BlendImageFilterProps props;
|
223
|
+
|
224
|
+
public:
|
225
|
+
BlendImageFilterCmd(jsi::Runtime &runtime, const jsi::Object &object,
|
226
|
+
Variables &variables)
|
227
|
+
: Command(CommandType::PushImageFilter, "skBlendImageFilter") {
|
228
|
+
convertProperty(runtime, object, "mode", props.mode, variables);
|
229
|
+
}
|
230
|
+
|
231
|
+
void pushImageFilter(DrawingCtx *ctx) {
|
232
|
+
// Get all filters
|
233
|
+
auto filters = std::move(ctx->imageFilters);
|
234
|
+
ctx->imageFilters.clear();
|
235
|
+
|
236
|
+
// Create composer function
|
237
|
+
auto composer = [this](sk_sp<SkImageFilter> outer,
|
238
|
+
sk_sp<SkImageFilter> inner) {
|
239
|
+
return SkImageFilters::Blend(props.mode, outer, inner);
|
240
|
+
};
|
241
|
+
|
242
|
+
// Compose filters
|
243
|
+
auto composedFilter = composeEffects<SkImageFilter>(filters, composer);
|
244
|
+
|
245
|
+
if (composedFilter) {
|
246
|
+
ctx->imageFilters.push_back(composedFilter);
|
247
|
+
}
|
248
|
+
}
|
249
|
+
};
|
250
|
+
|
251
|
+
struct RuntimeShaderImageFilterProps {
|
252
|
+
sk_sp<SkRuntimeEffect> source;
|
253
|
+
std::optional<Uniforms> uniforms;
|
254
|
+
};
|
255
|
+
|
256
|
+
class RuntimeShaderImageFilterCmd : public Command {
|
257
|
+
private:
|
258
|
+
RuntimeShaderImageFilterProps props;
|
259
|
+
|
260
|
+
public:
|
261
|
+
RuntimeShaderImageFilterCmd(jsi::Runtime &runtime, const jsi::Object &object,
|
262
|
+
Variables &variables)
|
263
|
+
: Command(CommandType::PushImageFilter, "skRuntimeShaderImageFilter") {
|
264
|
+
convertProperty(runtime, object, "source", props.source, variables);
|
265
|
+
convertProperty(runtime, object, "uniforms", props.uniforms, variables);
|
266
|
+
}
|
267
|
+
|
268
|
+
void pushImageFilter(DrawingCtx *ctx) {
|
269
|
+
if (props.source) {
|
270
|
+
// Create the runtime shader builder
|
271
|
+
SkRuntimeShaderBuilder builder(props.source);
|
272
|
+
|
273
|
+
// Process uniforms if present
|
274
|
+
if (props.uniforms.has_value()) {
|
275
|
+
processUniforms(builder, props.source, props.uniforms.value());
|
276
|
+
}
|
277
|
+
|
278
|
+
// Get the input filter (if any)
|
279
|
+
sk_sp<SkImageFilter> input = nullptr;
|
280
|
+
if (!ctx->imageFilters.empty()) {
|
281
|
+
input = ctx->imageFilters.back();
|
282
|
+
ctx->imageFilters.pop_back();
|
283
|
+
}
|
284
|
+
|
285
|
+
// Create and push the runtime shader image filter
|
286
|
+
auto imgf = SkImageFilters::RuntimeShader(builder, "", input);
|
287
|
+
ctx->imageFilters.push_back(imgf);
|
288
|
+
}
|
289
|
+
}
|
290
|
+
};
|
291
|
+
|
292
|
+
} // namespace RNSkia
|
@@ -0,0 +1,314 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
#include <memory>
|
4
|
+
#include <numeric>
|
5
|
+
#include <utility>
|
6
|
+
#include <vector>
|
7
|
+
|
8
|
+
#include "JsiSkCanvas.h"
|
9
|
+
#include "JsiSkHostObjects.h"
|
10
|
+
|
11
|
+
#include "DrawingCtx.h"
|
12
|
+
#include "RNRecorder.h"
|
13
|
+
#include "RNSkLog.h"
|
14
|
+
|
15
|
+
#include <jsi/jsi.h>
|
16
|
+
|
17
|
+
namespace RNSkia {
|
18
|
+
|
19
|
+
namespace jsi = facebook::jsi;
|
20
|
+
|
21
|
+
class JsiRecorder : public JsiSkWrappingSharedPtrHostObject<Recorder> {
|
22
|
+
public:
|
23
|
+
JsiRecorder(std::shared_ptr<RNSkPlatformContext> context)
|
24
|
+
: JsiSkWrappingSharedPtrHostObject(std::move(context),
|
25
|
+
std::make_shared<Recorder>()) {}
|
26
|
+
|
27
|
+
JSI_HOST_FUNCTION(savePaint) {
|
28
|
+
getObject()->savePaint(runtime, arguments[0].asObject(runtime));
|
29
|
+
return jsi::Value::undefined();
|
30
|
+
}
|
31
|
+
|
32
|
+
JSI_HOST_FUNCTION(materializePaint) {
|
33
|
+
getObject()->materializePaint();
|
34
|
+
return jsi::Value::undefined();
|
35
|
+
}
|
36
|
+
|
37
|
+
JSI_HOST_FUNCTION(drawCircle) {
|
38
|
+
getObject()->drawCircle(runtime, arguments[0].asObject(runtime));
|
39
|
+
return jsi::Value::undefined();
|
40
|
+
}
|
41
|
+
|
42
|
+
JSI_HOST_FUNCTION(restorePaint) {
|
43
|
+
getObject()->restorePaint();
|
44
|
+
return jsi::Value::undefined();
|
45
|
+
}
|
46
|
+
|
47
|
+
JSI_HOST_FUNCTION(drawPaint) {
|
48
|
+
getObject()->drawPaint();
|
49
|
+
return jsi::Value::undefined();
|
50
|
+
}
|
51
|
+
|
52
|
+
JSI_HOST_FUNCTION(play) {
|
53
|
+
auto jsiCanvas =
|
54
|
+
arguments[0].asObject(runtime).asHostObject<JsiSkCanvas>(runtime);
|
55
|
+
DrawingCtx ctx(jsiCanvas->getCanvas());
|
56
|
+
getObject()->play(&ctx);
|
57
|
+
return jsi::Value::undefined();
|
58
|
+
}
|
59
|
+
|
60
|
+
JSI_HOST_FUNCTION(applyUpdates) {
|
61
|
+
auto values = arguments[0].asObject(runtime).asArray(runtime);
|
62
|
+
auto size = values.size(runtime);
|
63
|
+
auto recorder = getObject();
|
64
|
+
for (int i = 0; i < size; i++) {
|
65
|
+
auto sharedValue = values.getValueAtIndex(runtime, i).asObject(runtime);
|
66
|
+
auto name = "variable" + std::to_string(i);
|
67
|
+
// Look up the conversion functions for this name
|
68
|
+
auto it = recorder->variables.find(name);
|
69
|
+
if (it != recorder->variables.end()) {
|
70
|
+
// Execute each conversion function in the vector
|
71
|
+
const auto &conversionFunctions = it->second;
|
72
|
+
for (const auto &conversionFunc : conversionFunctions) {
|
73
|
+
conversionFunc(runtime, sharedValue);
|
74
|
+
}
|
75
|
+
}
|
76
|
+
}
|
77
|
+
return jsi::Value::undefined();
|
78
|
+
}
|
79
|
+
|
80
|
+
JSI_HOST_FUNCTION(saveGroup) {
|
81
|
+
getObject()->saveGroup();
|
82
|
+
return jsi::Value::undefined();
|
83
|
+
}
|
84
|
+
|
85
|
+
JSI_HOST_FUNCTION(restoreGroup) {
|
86
|
+
getObject()->restoreGroup();
|
87
|
+
return jsi::Value::undefined();
|
88
|
+
}
|
89
|
+
|
90
|
+
JSI_HOST_FUNCTION(restorePaintDeclaration) {
|
91
|
+
getObject()->restorePaintDeclaration();
|
92
|
+
return jsi::Value::undefined();
|
93
|
+
}
|
94
|
+
|
95
|
+
JSI_HOST_FUNCTION(pushPathEffect) {
|
96
|
+
getObject()->pushPathEffect(runtime,
|
97
|
+
arguments[0].asString(runtime).utf8(runtime),
|
98
|
+
arguments[1].asObject(runtime));
|
99
|
+
return jsi::Value::undefined();
|
100
|
+
}
|
101
|
+
|
102
|
+
JSI_HOST_FUNCTION(pushImageFilter) {
|
103
|
+
getObject()->pushImageFilter(runtime,
|
104
|
+
arguments[0].asString(runtime).utf8(runtime),
|
105
|
+
arguments[1].asObject(runtime));
|
106
|
+
return jsi::Value::undefined();
|
107
|
+
}
|
108
|
+
|
109
|
+
JSI_HOST_FUNCTION(pushColorFilter) {
|
110
|
+
getObject()->pushColorFilter(runtime,
|
111
|
+
arguments[0].asString(runtime).utf8(runtime),
|
112
|
+
arguments[1].asObject(runtime));
|
113
|
+
return jsi::Value::undefined();
|
114
|
+
}
|
115
|
+
|
116
|
+
JSI_HOST_FUNCTION(pushShader) {
|
117
|
+
getObject()->pushShader(runtime,
|
118
|
+
arguments[0].asString(runtime).utf8(runtime),
|
119
|
+
arguments[1].asObject(runtime));
|
120
|
+
return jsi::Value::undefined();
|
121
|
+
}
|
122
|
+
|
123
|
+
JSI_HOST_FUNCTION(pushBlurMaskFilter) {
|
124
|
+
getObject()->pushBlurMaskFilter(runtime, arguments[0].asObject(runtime));
|
125
|
+
return jsi::Value::undefined();
|
126
|
+
}
|
127
|
+
|
128
|
+
JSI_HOST_FUNCTION(composePathEffect) {
|
129
|
+
getObject()->composePathEffect();
|
130
|
+
return jsi::Value::undefined();
|
131
|
+
}
|
132
|
+
|
133
|
+
JSI_HOST_FUNCTION(composeColorFilter) {
|
134
|
+
getObject()->composeColorFilter();
|
135
|
+
return jsi::Value::undefined();
|
136
|
+
}
|
137
|
+
|
138
|
+
JSI_HOST_FUNCTION(composeImageFilter) {
|
139
|
+
getObject()->composeImageFilter();
|
140
|
+
return jsi::Value::undefined();
|
141
|
+
}
|
142
|
+
|
143
|
+
JSI_HOST_FUNCTION(saveCTM) {
|
144
|
+
getObject()->saveCTM(runtime, arguments[0].asObject(runtime));
|
145
|
+
return jsi::Value::undefined();
|
146
|
+
}
|
147
|
+
|
148
|
+
JSI_HOST_FUNCTION(restoreCTM) {
|
149
|
+
getObject()->restoreCTM();
|
150
|
+
return jsi::Value::undefined();
|
151
|
+
}
|
152
|
+
|
153
|
+
JSI_HOST_FUNCTION(saveLayer) {
|
154
|
+
getObject()->saveLayer();
|
155
|
+
return jsi::Value::undefined();
|
156
|
+
}
|
157
|
+
|
158
|
+
JSI_HOST_FUNCTION(saveBackdropFilter) {
|
159
|
+
getObject()->saveBackdropFilter();
|
160
|
+
return jsi::Value::undefined();
|
161
|
+
}
|
162
|
+
|
163
|
+
JSI_HOST_FUNCTION(drawBox) {
|
164
|
+
auto boxProps = arguments[0].asObject(runtime);
|
165
|
+
auto shadowsArray = arguments[1].asObject(runtime).asArray(runtime);
|
166
|
+
getObject()->drawBox(runtime, boxProps, shadowsArray);
|
167
|
+
return jsi::Value::undefined();
|
168
|
+
}
|
169
|
+
|
170
|
+
JSI_HOST_FUNCTION(drawImage) {
|
171
|
+
getObject()->drawImage(runtime, arguments[0].asObject(runtime));
|
172
|
+
return jsi::Value::undefined();
|
173
|
+
}
|
174
|
+
|
175
|
+
JSI_HOST_FUNCTION(drawPoints) {
|
176
|
+
getObject()->drawPoints(runtime, arguments[0].asObject(runtime));
|
177
|
+
return jsi::Value::undefined();
|
178
|
+
}
|
179
|
+
|
180
|
+
JSI_HOST_FUNCTION(drawPath) {
|
181
|
+
getObject()->drawPath(runtime, arguments[0].asObject(runtime));
|
182
|
+
return jsi::Value::undefined();
|
183
|
+
}
|
184
|
+
|
185
|
+
JSI_HOST_FUNCTION(drawRect) {
|
186
|
+
getObject()->drawRect(runtime, arguments[0].asObject(runtime));
|
187
|
+
return jsi::Value::undefined();
|
188
|
+
}
|
189
|
+
|
190
|
+
JSI_HOST_FUNCTION(drawRRect) {
|
191
|
+
getObject()->drawRRect(runtime, arguments[0].asObject(runtime));
|
192
|
+
return jsi::Value::undefined();
|
193
|
+
}
|
194
|
+
|
195
|
+
JSI_HOST_FUNCTION(drawOval) {
|
196
|
+
getObject()->drawOval(runtime, arguments[0].asObject(runtime));
|
197
|
+
return jsi::Value::undefined();
|
198
|
+
}
|
199
|
+
|
200
|
+
JSI_HOST_FUNCTION(drawLine) {
|
201
|
+
getObject()->drawLine(runtime, arguments[0].asObject(runtime));
|
202
|
+
return jsi::Value::undefined();
|
203
|
+
}
|
204
|
+
|
205
|
+
JSI_HOST_FUNCTION(drawPatch) {
|
206
|
+
getObject()->drawPatch(runtime, arguments[0].asObject(runtime));
|
207
|
+
return jsi::Value::undefined();
|
208
|
+
}
|
209
|
+
|
210
|
+
JSI_HOST_FUNCTION(drawVertices) {
|
211
|
+
getObject()->drawVertices(runtime, arguments[0].asObject(runtime));
|
212
|
+
return jsi::Value::undefined();
|
213
|
+
}
|
214
|
+
|
215
|
+
JSI_HOST_FUNCTION(drawDiffRect) {
|
216
|
+
getObject()->drawDiffRect(runtime, arguments[0].asObject(runtime));
|
217
|
+
return jsi::Value::undefined();
|
218
|
+
}
|
219
|
+
|
220
|
+
JSI_HOST_FUNCTION(drawText) {
|
221
|
+
getObject()->drawText(runtime, arguments[0].asObject(runtime));
|
222
|
+
return jsi::Value::undefined();
|
223
|
+
}
|
224
|
+
|
225
|
+
JSI_HOST_FUNCTION(drawTextPath) {
|
226
|
+
getObject()->drawTextPath(runtime, arguments[0].asObject(runtime));
|
227
|
+
return jsi::Value::undefined();
|
228
|
+
}
|
229
|
+
|
230
|
+
JSI_HOST_FUNCTION(drawTextBlob) {
|
231
|
+
getObject()->drawTextBlob(runtime, arguments[0].asObject(runtime));
|
232
|
+
return jsi::Value::undefined();
|
233
|
+
}
|
234
|
+
|
235
|
+
JSI_HOST_FUNCTION(drawGlyphs) {
|
236
|
+
getObject()->drawGlyphs(runtime, arguments[0].asObject(runtime));
|
237
|
+
return jsi::Value::undefined();
|
238
|
+
}
|
239
|
+
|
240
|
+
JSI_HOST_FUNCTION(drawPicture) {
|
241
|
+
getObject()->drawPicture(runtime, arguments[0].asObject(runtime));
|
242
|
+
return jsi::Value::undefined();
|
243
|
+
}
|
244
|
+
|
245
|
+
JSI_HOST_FUNCTION(drawImageSVG) {
|
246
|
+
getObject()->drawImageSVG(runtime, arguments[0].asObject(runtime));
|
247
|
+
return jsi::Value::undefined();
|
248
|
+
}
|
249
|
+
|
250
|
+
JSI_HOST_FUNCTION(drawParagraph) {
|
251
|
+
getObject()->drawParagraph(runtime, arguments[0].asObject(runtime));
|
252
|
+
return jsi::Value::undefined();
|
253
|
+
}
|
254
|
+
|
255
|
+
JSI_HOST_FUNCTION(drawAtlas) {
|
256
|
+
getObject()->drawAtlas(runtime, arguments[0].asObject(runtime));
|
257
|
+
return jsi::Value::undefined();
|
258
|
+
}
|
259
|
+
|
260
|
+
EXPORT_JSI_API_TYPENAME(JsiRecorder, Recorder)
|
261
|
+
|
262
|
+
JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiRecorder, saveGroup),
|
263
|
+
JSI_EXPORT_FUNC(JsiRecorder, restoreGroup),
|
264
|
+
JSI_EXPORT_FUNC(JsiRecorder, savePaint),
|
265
|
+
JSI_EXPORT_FUNC(JsiRecorder, restorePaint),
|
266
|
+
JSI_EXPORT_FUNC(JsiRecorder, restorePaintDeclaration),
|
267
|
+
JSI_EXPORT_FUNC(JsiRecorder, materializePaint),
|
268
|
+
JSI_EXPORT_FUNC(JsiRecorder, pushPathEffect),
|
269
|
+
JSI_EXPORT_FUNC(JsiRecorder, pushImageFilter),
|
270
|
+
JSI_EXPORT_FUNC(JsiRecorder, pushColorFilter),
|
271
|
+
JSI_EXPORT_FUNC(JsiRecorder, pushShader),
|
272
|
+
JSI_EXPORT_FUNC(JsiRecorder, pushBlurMaskFilter),
|
273
|
+
JSI_EXPORT_FUNC(JsiRecorder, composePathEffect),
|
274
|
+
JSI_EXPORT_FUNC(JsiRecorder, composeColorFilter),
|
275
|
+
JSI_EXPORT_FUNC(JsiRecorder, composeImageFilter),
|
276
|
+
JSI_EXPORT_FUNC(JsiRecorder, saveCTM),
|
277
|
+
JSI_EXPORT_FUNC(JsiRecorder, restoreCTM),
|
278
|
+
JSI_EXPORT_FUNC(JsiRecorder, drawPaint),
|
279
|
+
JSI_EXPORT_FUNC(JsiRecorder, saveLayer),
|
280
|
+
JSI_EXPORT_FUNC(JsiRecorder, saveBackdropFilter),
|
281
|
+
JSI_EXPORT_FUNC(JsiRecorder, drawBox),
|
282
|
+
JSI_EXPORT_FUNC(JsiRecorder, drawImage),
|
283
|
+
JSI_EXPORT_FUNC(JsiRecorder, drawCircle),
|
284
|
+
JSI_EXPORT_FUNC(JsiRecorder, drawPoints),
|
285
|
+
JSI_EXPORT_FUNC(JsiRecorder, drawPath),
|
286
|
+
JSI_EXPORT_FUNC(JsiRecorder, drawRect),
|
287
|
+
JSI_EXPORT_FUNC(JsiRecorder, drawRRect),
|
288
|
+
JSI_EXPORT_FUNC(JsiRecorder, drawOval),
|
289
|
+
JSI_EXPORT_FUNC(JsiRecorder, drawLine),
|
290
|
+
JSI_EXPORT_FUNC(JsiRecorder, drawPatch),
|
291
|
+
JSI_EXPORT_FUNC(JsiRecorder, drawVertices),
|
292
|
+
JSI_EXPORT_FUNC(JsiRecorder, drawDiffRect),
|
293
|
+
JSI_EXPORT_FUNC(JsiRecorder, drawText),
|
294
|
+
JSI_EXPORT_FUNC(JsiRecorder, drawTextPath),
|
295
|
+
JSI_EXPORT_FUNC(JsiRecorder, drawTextBlob),
|
296
|
+
JSI_EXPORT_FUNC(JsiRecorder, drawGlyphs),
|
297
|
+
JSI_EXPORT_FUNC(JsiRecorder, drawPicture),
|
298
|
+
JSI_EXPORT_FUNC(JsiRecorder, drawImageSVG),
|
299
|
+
JSI_EXPORT_FUNC(JsiRecorder, drawParagraph),
|
300
|
+
JSI_EXPORT_FUNC(JsiRecorder, drawAtlas),
|
301
|
+
JSI_EXPORT_FUNC(JsiRecorder, play),
|
302
|
+
JSI_EXPORT_FUNC(JsiRecorder, applyUpdates))
|
303
|
+
|
304
|
+
static const jsi::HostFunctionType
|
305
|
+
createCtor(std::shared_ptr<RNSkPlatformContext> context) {
|
306
|
+
return JSI_HOST_FUNCTION_LAMBDA {
|
307
|
+
// Return the newly constructed object
|
308
|
+
return jsi::Object::createFromHostObject(
|
309
|
+
runtime, std::make_shared<JsiRecorder>(std::move(context)));
|
310
|
+
};
|
311
|
+
}
|
312
|
+
};
|
313
|
+
|
314
|
+
} // namespace RNSkia
|