@shopify/react-native-skia 2.2.6 → 2.2.8
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.
- package/cpp/api/recorder/DrawingCtx.h +15 -0
- package/cpp/api/recorder/JsiRecorder.h +2 -1
- package/cpp/api/recorder/RNRecorder.h +2 -2
- package/cpp/api/recorder/Shaders.h +6 -5
- package/lib/commonjs/skia/types/Recorder.d.ts +1 -1
- package/lib/commonjs/skia/types/Recorder.js.map +1 -1
- package/lib/commonjs/sksg/Container.d.ts +3 -39
- package/lib/commonjs/sksg/Container.js +3 -195
- package/lib/commonjs/sksg/Container.js.map +1 -1
- package/lib/commonjs/sksg/Container.native.d.ts +14 -0
- package/lib/commonjs/sksg/Container.native.js +81 -0
- package/lib/commonjs/sksg/Container.native.js.map +1 -0
- package/lib/commonjs/sksg/Container.web.d.ts +14 -0
- package/lib/commonjs/sksg/Container.web.js +91 -0
- package/lib/commonjs/sksg/Container.web.js.map +1 -0
- package/lib/commonjs/sksg/HostConfig.d.ts +1 -1
- package/lib/commonjs/sksg/HostConfig.js.map +1 -1
- package/lib/commonjs/sksg/Reconciler.js.map +1 -1
- package/lib/commonjs/sksg/Recorder/ReanimatedRecorder.d.ts +1 -1
- package/lib/commonjs/sksg/Recorder/ReanimatedRecorder.js +2 -2
- package/lib/commonjs/sksg/Recorder/ReanimatedRecorder.js.map +1 -1
- package/lib/commonjs/sksg/Recorder/Recorder.d.ts +1 -1
- package/lib/commonjs/sksg/Recorder/Recorder.js +3 -2
- package/lib/commonjs/sksg/Recorder/Recorder.js.map +1 -1
- package/lib/commonjs/sksg/Recorder/Visitor.js +2 -2
- package/lib/commonjs/sksg/Recorder/Visitor.js.map +1 -1
- package/lib/commonjs/sksg/Recorder/commands/Shaders.js +3 -3
- package/lib/commonjs/sksg/Recorder/commands/Shaders.js.map +1 -1
- package/lib/commonjs/sksg/StaticContainer.d.ts +24 -0
- package/lib/commonjs/sksg/StaticContainer.js +70 -0
- package/lib/commonjs/sksg/StaticContainer.js.map +1 -0
- package/lib/module/skia/types/Recorder.d.ts +1 -1
- package/lib/module/skia/types/Recorder.js.map +1 -1
- package/lib/module/sksg/Container.d.ts +3 -39
- package/lib/module/sksg/Container.js +2 -192
- package/lib/module/sksg/Container.js.map +1 -1
- package/lib/module/sksg/Container.native.d.ts +14 -0
- package/lib/module/sksg/Container.native.js +73 -0
- package/lib/module/sksg/Container.native.js.map +1 -0
- package/lib/module/sksg/Container.web.d.ts +14 -0
- package/lib/module/sksg/Container.web.js +83 -0
- package/lib/module/sksg/Container.web.js.map +1 -0
- package/lib/module/sksg/HostConfig.d.ts +1 -1
- package/lib/module/sksg/HostConfig.js.map +1 -1
- package/lib/module/sksg/Reconciler.js.map +1 -1
- package/lib/module/sksg/Recorder/ReanimatedRecorder.d.ts +1 -1
- package/lib/module/sksg/Recorder/ReanimatedRecorder.js +2 -2
- package/lib/module/sksg/Recorder/ReanimatedRecorder.js.map +1 -1
- package/lib/module/sksg/Recorder/Recorder.d.ts +1 -1
- package/lib/module/sksg/Recorder/Recorder.js +3 -2
- package/lib/module/sksg/Recorder/Recorder.js.map +1 -1
- package/lib/module/sksg/Recorder/Visitor.js +2 -2
- package/lib/module/sksg/Recorder/Visitor.js.map +1 -1
- package/lib/module/sksg/Recorder/commands/Shaders.js +3 -3
- package/lib/module/sksg/Recorder/commands/Shaders.js.map +1 -1
- package/lib/module/sksg/StaticContainer.d.ts +24 -0
- package/lib/module/sksg/StaticContainer.js +62 -0
- package/lib/module/sksg/StaticContainer.js.map +1 -0
- package/lib/typescript/lib/commonjs/sksg/Container.d.ts +2 -42
- package/lib/typescript/lib/commonjs/sksg/Container.native.d.ts +11 -0
- package/lib/typescript/lib/commonjs/sksg/Container.web.d.ts +15 -0
- package/lib/typescript/lib/commonjs/sksg/Reconciler.d.ts +1 -45
- package/lib/typescript/lib/commonjs/sksg/Recorder/ReanimatedRecorder.d.ts +1 -1
- package/lib/typescript/lib/commonjs/sksg/Recorder/Recorder.d.ts +1 -1
- package/lib/typescript/lib/commonjs/sksg/StaticContainer.d.ts +23 -0
- package/lib/typescript/lib/module/sksg/Container.d.ts +2 -42
- package/lib/typescript/lib/module/sksg/Container.native.d.ts +11 -0
- package/lib/typescript/lib/module/sksg/Container.web.d.ts +15 -0
- package/lib/typescript/lib/module/sksg/Reconciler.d.ts +1 -45
- package/lib/typescript/lib/module/sksg/Recorder/ReanimatedRecorder.d.ts +1 -1
- package/lib/typescript/lib/module/sksg/Recorder/Recorder.d.ts +1 -1
- package/lib/typescript/lib/module/sksg/StaticContainer.d.ts +22 -0
- package/lib/typescript/src/skia/types/Recorder.d.ts +1 -1
- package/lib/typescript/src/sksg/Container.d.ts +3 -39
- package/lib/typescript/src/sksg/Container.native.d.ts +14 -0
- package/lib/typescript/src/sksg/Container.web.d.ts +14 -0
- package/lib/typescript/src/sksg/HostConfig.d.ts +1 -1
- package/lib/typescript/src/sksg/Recorder/ReanimatedRecorder.d.ts +1 -1
- package/lib/typescript/src/sksg/Recorder/Recorder.d.ts +1 -1
- package/lib/typescript/src/sksg/StaticContainer.d.ts +24 -0
- package/package.json +1 -1
- package/src/renderer/__tests__/e2e/Shader.spec.tsx +93 -0
- package/src/skia/types/Recorder.ts +5 -1
- package/src/sksg/Container.native.ts +86 -0
- package/src/sksg/Container.ts +3 -223
- package/src/sksg/Container.web.ts +95 -0
- package/src/sksg/HostConfig.ts +1 -1
- package/src/sksg/Reconciler.ts +1 -1
- package/src/sksg/Recorder/ReanimatedRecorder.ts +6 -2
- package/src/sksg/Recorder/Recorder.ts +6 -2
- package/src/sksg/Recorder/Visitor.ts +2 -2
- package/src/sksg/Recorder/commands/Shaders.ts +8 -3
- package/src/sksg/StaticContainer.ts +83 -0
@@ -48,7 +48,11 @@ export interface BaseRecorder {
|
|
48
48
|
colorFilterType: NodeType,
|
49
49
|
props: AnimatedProps<unknown>
|
50
50
|
): void;
|
51
|
-
pushShader(
|
51
|
+
pushShader(
|
52
|
+
shaderType: NodeType,
|
53
|
+
props: AnimatedProps<unknown>,
|
54
|
+
children: number
|
55
|
+
): void;
|
52
56
|
pushBlurMaskFilter(props: AnimatedProps<BlurMaskFilterProps>): void;
|
53
57
|
composePathEffect(): void;
|
54
58
|
composeColorFilter(): void;
|
@@ -0,0 +1,86 @@
|
|
1
|
+
import type { SharedValue } from "react-native-reanimated";
|
2
|
+
|
3
|
+
import Rea from "../external/reanimated/ReanimatedProxy";
|
4
|
+
import type { Skia, SkSize } from "../skia/types";
|
5
|
+
import { HAS_REANIMATED_3 } from "../external/reanimated/renderHelpers";
|
6
|
+
import type { JsiRecorder } from "../skia/types/Recorder";
|
7
|
+
|
8
|
+
import { ReanimatedRecorder } from "./Recorder/ReanimatedRecorder";
|
9
|
+
import { Container, StaticContainer } from "./StaticContainer";
|
10
|
+
import { visit } from "./Recorder/Visitor";
|
11
|
+
|
12
|
+
import "../skia/NativeSetup";
|
13
|
+
import "../views/api";
|
14
|
+
|
15
|
+
const nativeDrawOnscreen = (
|
16
|
+
nativeId: number,
|
17
|
+
recorder: JsiRecorder,
|
18
|
+
onSize?: SharedValue<SkSize>
|
19
|
+
) => {
|
20
|
+
"worklet";
|
21
|
+
|
22
|
+
//const start = performance.now();
|
23
|
+
if (onSize) {
|
24
|
+
const size = SkiaViewApi.size(nativeId);
|
25
|
+
if (
|
26
|
+
size.width !== onSize.value.width ||
|
27
|
+
size.height !== onSize.value.height
|
28
|
+
) {
|
29
|
+
onSize.value = size;
|
30
|
+
}
|
31
|
+
}
|
32
|
+
const picture = recorder.play();
|
33
|
+
//const end = performance.now();
|
34
|
+
//console.log("Recording time: ", end - start);
|
35
|
+
SkiaViewApi.setJsiProperty(nativeId, "picture", picture);
|
36
|
+
};
|
37
|
+
|
38
|
+
class NativeReanimatedContainer extends Container {
|
39
|
+
private mapperId: number | null = null;
|
40
|
+
|
41
|
+
constructor(
|
42
|
+
Skia: Skia,
|
43
|
+
private nativeId: number,
|
44
|
+
private onSize?: SharedValue<SkSize>
|
45
|
+
) {
|
46
|
+
super(Skia);
|
47
|
+
}
|
48
|
+
|
49
|
+
redraw() {
|
50
|
+
if (this.mapperId !== null) {
|
51
|
+
Rea.stopMapper(this.mapperId);
|
52
|
+
}
|
53
|
+
if (this.unmounted) {
|
54
|
+
return;
|
55
|
+
}
|
56
|
+
const { nativeId, Skia } = this;
|
57
|
+
const recorder = new ReanimatedRecorder(Skia);
|
58
|
+
visit(recorder, this.root);
|
59
|
+
const sharedValues = recorder.getSharedValues();
|
60
|
+
const sharedRecorder = recorder.getRecorder();
|
61
|
+
Rea.runOnUI((onSize?: SharedValue<SkSize>) => {
|
62
|
+
"worklet";
|
63
|
+
nativeDrawOnscreen(nativeId, sharedRecorder, onSize);
|
64
|
+
})(this.onSize);
|
65
|
+
if (sharedValues.length > 0) {
|
66
|
+
const { onSize } = this;
|
67
|
+
this.mapperId = Rea.startMapper(() => {
|
68
|
+
"worklet";
|
69
|
+
sharedRecorder.applyUpdates(sharedValues);
|
70
|
+
nativeDrawOnscreen(nativeId, sharedRecorder, onSize);
|
71
|
+
}, sharedValues);
|
72
|
+
}
|
73
|
+
}
|
74
|
+
}
|
75
|
+
|
76
|
+
export const createContainer = (
|
77
|
+
Skia: Skia,
|
78
|
+
nativeId: number,
|
79
|
+
onSize?: SharedValue<SkSize>
|
80
|
+
) => {
|
81
|
+
if (HAS_REANIMATED_3 && nativeId !== -1) {
|
82
|
+
return new NativeReanimatedContainer(Skia, nativeId, onSize);
|
83
|
+
} else {
|
84
|
+
return new StaticContainer(Skia, nativeId);
|
85
|
+
}
|
86
|
+
};
|
package/src/sksg/Container.ts
CHANGED
@@ -1,233 +1,13 @@
|
|
1
1
|
import type { SharedValue } from "react-native-reanimated";
|
2
2
|
|
3
|
-
import
|
4
|
-
import type { Skia, SkCanvas, SkSize } from "../skia/types";
|
5
|
-
import { HAS_REANIMATED_3 } from "../external/reanimated/renderHelpers";
|
6
|
-
import type { JsiRecorder } from "../skia/types/Recorder";
|
3
|
+
import type { Skia, SkSize } from "../skia/types";
|
7
4
|
|
8
|
-
import
|
9
|
-
import type { Recording } from "./Recorder/Recorder";
|
10
|
-
import { Recorder } from "./Recorder/Recorder";
|
11
|
-
import { visit } from "./Recorder/Visitor";
|
12
|
-
import { replay } from "./Recorder/Player";
|
13
|
-
import { createDrawingContext } from "./Recorder/DrawingContext";
|
14
|
-
import { ReanimatedRecorder } from "./Recorder/ReanimatedRecorder";
|
15
|
-
|
16
|
-
import "../views/api";
|
17
|
-
|
18
|
-
const drawOnscreen = (
|
19
|
-
Skia: Skia,
|
20
|
-
nativeId: number,
|
21
|
-
recording: Recording,
|
22
|
-
onSize?: SharedValue<SkSize>
|
23
|
-
) => {
|
24
|
-
"worklet";
|
25
|
-
if (onSize) {
|
26
|
-
const size = SkiaViewApi.size(nativeId);
|
27
|
-
if (
|
28
|
-
size.width !== onSize.value.width ||
|
29
|
-
size.height !== onSize.value.height
|
30
|
-
) {
|
31
|
-
onSize.value = size;
|
32
|
-
}
|
33
|
-
}
|
34
|
-
const rec = Skia.PictureRecorder();
|
35
|
-
const canvas = rec.beginRecording();
|
36
|
-
//const start = performance.now();
|
37
|
-
|
38
|
-
const ctx = createDrawingContext(Skia, recording.paintPool, canvas);
|
39
|
-
replay(ctx, recording.commands);
|
40
|
-
const picture = rec.finishRecordingAsPicture();
|
41
|
-
//const end = performance.now();
|
42
|
-
//console.log("Recording time: ", end - start);
|
43
|
-
SkiaViewApi.setJsiProperty(nativeId, "picture", picture);
|
44
|
-
};
|
45
|
-
|
46
|
-
const nativeDrawOnscreen = (
|
47
|
-
nativeId: number,
|
48
|
-
recorder: JsiRecorder,
|
49
|
-
onSize?: SharedValue<SkSize>
|
50
|
-
) => {
|
51
|
-
"worklet";
|
52
|
-
|
53
|
-
//const start = performance.now();
|
54
|
-
if (onSize) {
|
55
|
-
const size = SkiaViewApi.size(nativeId);
|
56
|
-
if (
|
57
|
-
size.width !== onSize.value.width ||
|
58
|
-
size.height !== onSize.value.height
|
59
|
-
) {
|
60
|
-
onSize.value = size;
|
61
|
-
}
|
62
|
-
}
|
63
|
-
const picture = recorder.play();
|
64
|
-
//const end = performance.now();
|
65
|
-
//console.log("Recording time: ", end - start);
|
66
|
-
SkiaViewApi.setJsiProperty(nativeId, "picture", picture);
|
67
|
-
};
|
68
|
-
|
69
|
-
export abstract class Container {
|
70
|
-
private _root: Node[] = [];
|
71
|
-
protected recording: Recording | null = null;
|
72
|
-
protected unmounted = false;
|
73
|
-
|
74
|
-
constructor(protected Skia: Skia) {}
|
75
|
-
|
76
|
-
get root() {
|
77
|
-
return this._root;
|
78
|
-
}
|
79
|
-
|
80
|
-
set root(value: Node[]) {
|
81
|
-
this._root = value;
|
82
|
-
}
|
83
|
-
|
84
|
-
mount() {
|
85
|
-
this.unmounted = false;
|
86
|
-
}
|
87
|
-
|
88
|
-
unmount() {
|
89
|
-
this.unmounted = true;
|
90
|
-
}
|
91
|
-
|
92
|
-
drawOnCanvas(canvas: SkCanvas) {
|
93
|
-
if (!this.recording) {
|
94
|
-
throw new Error("No recording to draw");
|
95
|
-
}
|
96
|
-
const ctx = createDrawingContext(
|
97
|
-
this.Skia,
|
98
|
-
this.recording.paintPool,
|
99
|
-
canvas
|
100
|
-
);
|
101
|
-
replay(ctx, this.recording.commands);
|
102
|
-
}
|
103
|
-
|
104
|
-
abstract redraw(): void;
|
105
|
-
}
|
106
|
-
|
107
|
-
class StaticContainer extends Container {
|
108
|
-
constructor(
|
109
|
-
Skia: Skia,
|
110
|
-
private nativeId: number,
|
111
|
-
private onSize?: SharedValue<SkSize>
|
112
|
-
) {
|
113
|
-
super(Skia);
|
114
|
-
}
|
115
|
-
|
116
|
-
redraw() {
|
117
|
-
const recorder = new Recorder();
|
118
|
-
visit(recorder, this.root);
|
119
|
-
this.recording = recorder.getRecording();
|
120
|
-
const isOnScreen = this.nativeId !== -1;
|
121
|
-
if (isOnScreen) {
|
122
|
-
if (this.onSize) {
|
123
|
-
const size = SkiaViewApi.size(this.nativeId);
|
124
|
-
if (
|
125
|
-
size.width !== this.onSize.value.width ||
|
126
|
-
size.height !== this.onSize.value.height
|
127
|
-
) {
|
128
|
-
this.onSize.value = size;
|
129
|
-
}
|
130
|
-
}
|
131
|
-
const rec = this.Skia.PictureRecorder();
|
132
|
-
const canvas = rec.beginRecording();
|
133
|
-
this.drawOnCanvas(canvas);
|
134
|
-
const picture = rec.finishRecordingAsPicture();
|
135
|
-
SkiaViewApi.setJsiProperty(this.nativeId, "picture", picture);
|
136
|
-
}
|
137
|
-
}
|
138
|
-
}
|
139
|
-
|
140
|
-
class ReanimatedContainer extends Container {
|
141
|
-
private mapperId: number | null = null;
|
142
|
-
|
143
|
-
constructor(
|
144
|
-
Skia: Skia,
|
145
|
-
private nativeId: number,
|
146
|
-
private onSize?: SharedValue<SkSize>
|
147
|
-
) {
|
148
|
-
super(Skia);
|
149
|
-
}
|
150
|
-
|
151
|
-
redraw() {
|
152
|
-
if (this.mapperId !== null) {
|
153
|
-
Rea.stopMapper(this.mapperId);
|
154
|
-
}
|
155
|
-
if (this.unmounted) {
|
156
|
-
return;
|
157
|
-
}
|
158
|
-
const recorder = new Recorder();
|
159
|
-
visit(recorder, this.root);
|
160
|
-
const record = recorder.getRecording();
|
161
|
-
const { animationValues } = record;
|
162
|
-
this.recording = {
|
163
|
-
commands: record.commands,
|
164
|
-
paintPool: record.paintPool,
|
165
|
-
};
|
166
|
-
const { nativeId, Skia, recording } = this;
|
167
|
-
if (animationValues.size > 0) {
|
168
|
-
this.mapperId = Rea.startMapper(() => {
|
169
|
-
"worklet";
|
170
|
-
drawOnscreen(Skia, nativeId, recording!);
|
171
|
-
}, Array.from(animationValues));
|
172
|
-
}
|
173
|
-
Rea.runOnUI((onSize?: SharedValue<SkSize>) => {
|
174
|
-
"worklet";
|
175
|
-
drawOnscreen(Skia, nativeId, recording!, onSize);
|
176
|
-
})(this.onSize);
|
177
|
-
}
|
178
|
-
}
|
179
|
-
|
180
|
-
class NativeReanimatedContainer extends Container {
|
181
|
-
private mapperId: number | null = null;
|
182
|
-
|
183
|
-
constructor(
|
184
|
-
Skia: Skia,
|
185
|
-
private nativeId: number,
|
186
|
-
private onSize?: SharedValue<SkSize>
|
187
|
-
) {
|
188
|
-
super(Skia);
|
189
|
-
}
|
190
|
-
|
191
|
-
redraw() {
|
192
|
-
if (this.mapperId !== null) {
|
193
|
-
Rea.stopMapper(this.mapperId);
|
194
|
-
}
|
195
|
-
if (this.unmounted) {
|
196
|
-
return;
|
197
|
-
}
|
198
|
-
const { nativeId, Skia } = this;
|
199
|
-
const recorder = new ReanimatedRecorder(Skia);
|
200
|
-
visit(recorder, this.root);
|
201
|
-
const sharedValues = recorder.getSharedValues();
|
202
|
-
const sharedRecorder = recorder.getRecorder();
|
203
|
-
Rea.runOnUI((onSize?: SharedValue<SkSize>) => {
|
204
|
-
"worklet";
|
205
|
-
nativeDrawOnscreen(nativeId, sharedRecorder, onSize);
|
206
|
-
})(this.onSize);
|
207
|
-
if (sharedValues.length > 0) {
|
208
|
-
const { onSize } = this;
|
209
|
-
this.mapperId = Rea.startMapper(() => {
|
210
|
-
"worklet";
|
211
|
-
sharedRecorder.applyUpdates(sharedValues);
|
212
|
-
nativeDrawOnscreen(nativeId, sharedRecorder, onSize);
|
213
|
-
}, sharedValues);
|
214
|
-
}
|
215
|
-
}
|
216
|
-
}
|
5
|
+
import { StaticContainer } from "./StaticContainer";
|
217
6
|
|
218
7
|
export const createContainer = (
|
219
8
|
Skia: Skia,
|
220
9
|
nativeId: number,
|
221
10
|
onSize?: SharedValue<SkSize>
|
222
11
|
) => {
|
223
|
-
|
224
|
-
if (HAS_REANIMATED_3 && nativeId !== -1) {
|
225
|
-
if (!web) {
|
226
|
-
return new NativeReanimatedContainer(Skia, nativeId, onSize);
|
227
|
-
} else {
|
228
|
-
return new ReanimatedContainer(Skia, nativeId, onSize);
|
229
|
-
}
|
230
|
-
} else {
|
231
|
-
return new StaticContainer(Skia, nativeId);
|
232
|
-
}
|
12
|
+
return new StaticContainer(Skia, nativeId, onSize);
|
233
13
|
};
|
@@ -0,0 +1,95 @@
|
|
1
|
+
import type { SharedValue } from "react-native-reanimated";
|
2
|
+
|
3
|
+
import Rea from "../external/reanimated/ReanimatedProxy";
|
4
|
+
import type { Skia, SkSize } from "../skia/types";
|
5
|
+
import { HAS_REANIMATED_3 } from "../external/reanimated/renderHelpers";
|
6
|
+
|
7
|
+
import type { Recording } from "./Recorder/Recorder";
|
8
|
+
import { Recorder } from "./Recorder/Recorder";
|
9
|
+
import { visit } from "./Recorder/Visitor";
|
10
|
+
import { replay } from "./Recorder/Player";
|
11
|
+
import { createDrawingContext } from "./Recorder/DrawingContext";
|
12
|
+
import { Container, StaticContainer } from "./StaticContainer";
|
13
|
+
|
14
|
+
import "../skia/NativeSetup";
|
15
|
+
import "../views/api";
|
16
|
+
|
17
|
+
const drawOnscreen = (
|
18
|
+
Skia: Skia,
|
19
|
+
nativeId: number,
|
20
|
+
recording: Recording,
|
21
|
+
onSize?: SharedValue<SkSize>
|
22
|
+
) => {
|
23
|
+
"worklet";
|
24
|
+
if (onSize) {
|
25
|
+
const size = SkiaViewApi.size(nativeId);
|
26
|
+
if (
|
27
|
+
size.width !== onSize.value.width ||
|
28
|
+
size.height !== onSize.value.height
|
29
|
+
) {
|
30
|
+
onSize.value = size;
|
31
|
+
}
|
32
|
+
}
|
33
|
+
const rec = Skia.PictureRecorder();
|
34
|
+
const canvas = rec.beginRecording();
|
35
|
+
//const start = performance.now();
|
36
|
+
|
37
|
+
const ctx = createDrawingContext(Skia, recording.paintPool, canvas);
|
38
|
+
replay(ctx, recording.commands);
|
39
|
+
const picture = rec.finishRecordingAsPicture();
|
40
|
+
//const end = performance.now();
|
41
|
+
//console.log("Recording time: ", end - start);
|
42
|
+
SkiaViewApi.setJsiProperty(nativeId, "picture", picture);
|
43
|
+
};
|
44
|
+
|
45
|
+
class ReanimatedContainer extends Container {
|
46
|
+
private mapperId: number | null = null;
|
47
|
+
|
48
|
+
constructor(
|
49
|
+
Skia: Skia,
|
50
|
+
private nativeId: number,
|
51
|
+
private onSize?: SharedValue<SkSize>
|
52
|
+
) {
|
53
|
+
super(Skia);
|
54
|
+
}
|
55
|
+
|
56
|
+
redraw() {
|
57
|
+
if (this.mapperId !== null) {
|
58
|
+
Rea.stopMapper(this.mapperId);
|
59
|
+
}
|
60
|
+
if (this.unmounted) {
|
61
|
+
return;
|
62
|
+
}
|
63
|
+
const recorder = new Recorder();
|
64
|
+
visit(recorder, this.root);
|
65
|
+
const record = recorder.getRecording();
|
66
|
+
const { animationValues } = record;
|
67
|
+
this.recording = {
|
68
|
+
commands: record.commands,
|
69
|
+
paintPool: record.paintPool,
|
70
|
+
};
|
71
|
+
const { nativeId, Skia, recording } = this;
|
72
|
+
if (animationValues.size > 0) {
|
73
|
+
this.mapperId = Rea.startMapper(() => {
|
74
|
+
"worklet";
|
75
|
+
drawOnscreen(Skia, nativeId, recording!);
|
76
|
+
}, Array.from(animationValues));
|
77
|
+
}
|
78
|
+
Rea.runOnUI((onSize?: SharedValue<SkSize>) => {
|
79
|
+
"worklet";
|
80
|
+
drawOnscreen(Skia, nativeId, recording!, onSize);
|
81
|
+
})(this.onSize);
|
82
|
+
}
|
83
|
+
}
|
84
|
+
|
85
|
+
export const createContainer = (
|
86
|
+
Skia: Skia,
|
87
|
+
nativeId: number,
|
88
|
+
onSize?: SharedValue<SkSize>
|
89
|
+
) => {
|
90
|
+
if (HAS_REANIMATED_3 && nativeId !== -1) {
|
91
|
+
return new ReanimatedContainer(Skia, nativeId, onSize);
|
92
|
+
} else {
|
93
|
+
return new StaticContainer(Skia, nativeId);
|
94
|
+
}
|
95
|
+
};
|
package/src/sksg/HostConfig.ts
CHANGED
@@ -7,7 +7,7 @@ import type { NodeType } from "../dom/types";
|
|
7
7
|
import { shallowEq } from "../renderer/typeddash";
|
8
8
|
|
9
9
|
import type { Node } from "./Node";
|
10
|
-
import type { Container } from "./
|
10
|
+
import type { Container } from "./StaticContainer";
|
11
11
|
|
12
12
|
type EventPriority = number;
|
13
13
|
const NoEventPriority = 0;
|
package/src/sksg/Reconciler.ts
CHANGED
@@ -7,7 +7,7 @@ import type { SkCanvas, Skia, SkSize } from "../skia/types";
|
|
7
7
|
import { NodeType } from "../dom/types";
|
8
8
|
|
9
9
|
import { debug, sksgHostConfig } from "./HostConfig";
|
10
|
-
import type { Container } from "./
|
10
|
+
import type { Container } from "./StaticContainer";
|
11
11
|
import { createContainer } from "./Container";
|
12
12
|
|
13
13
|
import "./Elements";
|
@@ -111,9 +111,13 @@ export class ReanimatedRecorder implements BaseRecorder {
|
|
111
111
|
this.recorder.pushColorFilter(colorFilterType, props);
|
112
112
|
}
|
113
113
|
|
114
|
-
pushShader(
|
114
|
+
pushShader(
|
115
|
+
shaderType: NodeType,
|
116
|
+
props: AnimatedProps<unknown>,
|
117
|
+
children: number
|
118
|
+
): void {
|
115
119
|
this.processAnimationValues(props);
|
116
|
-
this.recorder.pushShader(shaderType, props);
|
120
|
+
this.recorder.pushShader(shaderType, props, children);
|
117
121
|
}
|
118
122
|
|
119
123
|
pushBlurMaskFilter(props: AnimatedProps<BlurMaskFilterProps>): void {
|
@@ -152,11 +152,15 @@ export class Recorder implements BaseRecorder {
|
|
152
152
|
});
|
153
153
|
}
|
154
154
|
|
155
|
-
pushShader(
|
155
|
+
pushShader(
|
156
|
+
shaderType: NodeType,
|
157
|
+
props: AnimatedProps<unknown>,
|
158
|
+
children: number
|
159
|
+
) {
|
156
160
|
if (!isShader(shaderType) && !(shaderType === NodeType.Blend)) {
|
157
161
|
throw new Error("Invalid color filter type: " + shaderType);
|
158
162
|
}
|
159
|
-
this.add({ type: CommandType.PushShader, shaderType, props });
|
163
|
+
this.add({ type: CommandType.PushShader, shaderType, props, children });
|
160
164
|
}
|
161
165
|
|
162
166
|
pushBlurMaskFilter(props: AnimatedProps<BlurMaskFilterProps>) {
|
@@ -160,7 +160,7 @@ const pushImageFilters = (
|
|
160
160
|
if (isImageFilter(imageFilter.type)) {
|
161
161
|
recorder.pushImageFilter(imageFilter.type, imageFilter.props);
|
162
162
|
} else if (isShader(imageFilter.type)) {
|
163
|
-
recorder.pushShader(imageFilter.type, imageFilter.props);
|
163
|
+
recorder.pushShader(imageFilter.type, imageFilter.props, 0);
|
164
164
|
}
|
165
165
|
const needsComposition =
|
166
166
|
imageFilter.type !== NodeType.BlendImageFilter &&
|
@@ -176,7 +176,7 @@ const pushShaders = (recorder: BaseRecorder, shaders: Node<any>[]) => {
|
|
176
176
|
if (shader.children.length > 0) {
|
177
177
|
pushShaders(recorder, shader.children);
|
178
178
|
}
|
179
|
-
recorder.pushShader(shader.type, shader.props);
|
179
|
+
recorder.pushShader(shader.type, shader.props, shader.children.length);
|
180
180
|
});
|
181
181
|
};
|
182
182
|
|
@@ -34,14 +34,18 @@ import type { Command } from "../Core";
|
|
34
34
|
import { CommandType } from "../Core";
|
35
35
|
import type { DrawingContext } from "../DrawingContext";
|
36
36
|
|
37
|
-
const declareShader = (
|
37
|
+
const declareShader = (
|
38
|
+
ctx: DrawingContext,
|
39
|
+
props: ShaderProps,
|
40
|
+
children: number
|
41
|
+
) => {
|
38
42
|
"worklet";
|
39
43
|
const { source, uniforms, ...transform } = props;
|
40
44
|
const m3 = ctx.Skia.Matrix();
|
41
45
|
processTransformProps(m3, transform);
|
42
46
|
const shader = source.makeShaderWithChildren(
|
43
47
|
processUniforms(source, uniforms),
|
44
|
-
ctx.shaders.splice(0,
|
48
|
+
ctx.shaders.splice(0, children),
|
45
49
|
m3
|
46
50
|
);
|
47
51
|
ctx.shaders.push(shader);
|
@@ -257,6 +261,7 @@ interface PushShader<T extends keyof Props>
|
|
257
261
|
extends Command<CommandType.PushShader> {
|
258
262
|
shaderType: T;
|
259
263
|
props: Props[T];
|
264
|
+
children: number;
|
260
265
|
}
|
261
266
|
|
262
267
|
const isShader = <T extends keyof Props>(
|
@@ -273,7 +278,7 @@ export const pushShader = (
|
|
273
278
|
) => {
|
274
279
|
"worklet";
|
275
280
|
if (isShader(command, NodeType.Shader)) {
|
276
|
-
declareShader(ctx, command.props);
|
281
|
+
declareShader(ctx, command.props, command.children);
|
277
282
|
} else if (isShader(command, NodeType.ImageShader)) {
|
278
283
|
declareImageShader(ctx, command.props);
|
279
284
|
} else if (isShader(command, NodeType.ColorShader)) {
|
@@ -0,0 +1,83 @@
|
|
1
|
+
import type { SharedValue } from "react-native-reanimated";
|
2
|
+
|
3
|
+
import type { Skia, SkCanvas, SkSize } from "../skia/types";
|
4
|
+
|
5
|
+
import type { Node } from "./Node";
|
6
|
+
import type { Recording } from "./Recorder/Recorder";
|
7
|
+
import { Recorder } from "./Recorder/Recorder";
|
8
|
+
import { visit } from "./Recorder/Visitor";
|
9
|
+
import { replay } from "./Recorder/Player";
|
10
|
+
import { createDrawingContext } from "./Recorder/DrawingContext";
|
11
|
+
|
12
|
+
import "../views/api";
|
13
|
+
|
14
|
+
export abstract class Container {
|
15
|
+
private _root: Node[] = [];
|
16
|
+
protected recording: Recording | null = null;
|
17
|
+
protected unmounted = false;
|
18
|
+
|
19
|
+
constructor(protected Skia: Skia) {}
|
20
|
+
|
21
|
+
get root() {
|
22
|
+
return this._root;
|
23
|
+
}
|
24
|
+
|
25
|
+
set root(value: Node[]) {
|
26
|
+
this._root = value;
|
27
|
+
}
|
28
|
+
|
29
|
+
mount() {
|
30
|
+
this.unmounted = false;
|
31
|
+
}
|
32
|
+
|
33
|
+
unmount() {
|
34
|
+
this.unmounted = true;
|
35
|
+
}
|
36
|
+
|
37
|
+
drawOnCanvas(canvas: SkCanvas) {
|
38
|
+
if (!this.recording) {
|
39
|
+
throw new Error("No recording to draw");
|
40
|
+
}
|
41
|
+
const ctx = createDrawingContext(
|
42
|
+
this.Skia,
|
43
|
+
this.recording.paintPool,
|
44
|
+
canvas
|
45
|
+
);
|
46
|
+
replay(ctx, this.recording.commands);
|
47
|
+
}
|
48
|
+
|
49
|
+
abstract redraw(): void;
|
50
|
+
}
|
51
|
+
|
52
|
+
export class StaticContainer extends Container {
|
53
|
+
constructor(
|
54
|
+
Skia: Skia,
|
55
|
+
private nativeId: number,
|
56
|
+
private onSize?: SharedValue<SkSize>
|
57
|
+
) {
|
58
|
+
super(Skia);
|
59
|
+
}
|
60
|
+
|
61
|
+
redraw() {
|
62
|
+
const recorder = new Recorder();
|
63
|
+
visit(recorder, this.root);
|
64
|
+
this.recording = recorder.getRecording();
|
65
|
+
const isOnScreen = this.nativeId !== -1;
|
66
|
+
if (isOnScreen) {
|
67
|
+
if (this.onSize) {
|
68
|
+
const size = SkiaViewApi.size(this.nativeId);
|
69
|
+
if (
|
70
|
+
size.width !== this.onSize.value.width ||
|
71
|
+
size.height !== this.onSize.value.height
|
72
|
+
) {
|
73
|
+
this.onSize.value = size;
|
74
|
+
}
|
75
|
+
}
|
76
|
+
const rec = this.Skia.PictureRecorder();
|
77
|
+
const canvas = rec.beginRecording();
|
78
|
+
this.drawOnCanvas(canvas);
|
79
|
+
const picture = rec.finishRecordingAsPicture();
|
80
|
+
SkiaViewApi.setJsiProperty(this.nativeId, "picture", picture);
|
81
|
+
}
|
82
|
+
}
|
83
|
+
}
|