@shopify/react-native-skia 2.0.1 → 2.0.3
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/android/CMakeLists.txt +47 -21
- package/android/cpp/rnskia-android/RNSkAndroidPlatformContext.h +8 -5
- package/apple/MetalWindowContext.mm +4 -2
- package/apple/RNSkApplePlatformContext.h +7 -5
- package/apple/RNSkApplePlatformContext.mm +30 -29
- package/apple/SkiaCVPixelBufferUtils.mm +4 -8
- package/apple/SkiaManager.mm +0 -3
- package/cpp/api/JsiSkImageFactory.h +14 -1
- package/cpp/api/JsiSkSurface.h +7 -1
- package/cpp/api/recorder/DrawingCtx.h +19 -2
- package/cpp/api/recorder/Paint.h +1 -3
- package/cpp/api/recorder/RNRecorder.h +5 -13
- package/cpp/rnskia/DawnContext.h +11 -2
- package/cpp/rnskia/DawnUtils.h +97 -6
- package/cpp/rnskia/DawnWindowContext.h +18 -11
- package/cpp/rnskia/RNSkJsiViewApi.h +91 -71
- package/cpp/rnskia/RNSkManager.cpp +3 -18
- package/cpp/rnskia/RNSkManager.h +0 -6
- package/cpp/rnskia/RNSkPlatformContext.h +22 -5
- package/lib/commonjs/skia/types/Image/ImageFactory.d.ts +2 -1
- package/lib/commonjs/skia/types/Image/ImageFactory.js.map +1 -1
- package/lib/commonjs/skia/types/Surface/Surface.d.ts +1 -1
- package/lib/commonjs/skia/types/Surface/Surface.js.map +1 -1
- package/lib/commonjs/skia/web/JsiSkImageFactory.d.ts +1 -0
- package/lib/commonjs/skia/web/JsiSkImageFactory.js +3 -0
- package/lib/commonjs/skia/web/JsiSkImageFactory.js.map +1 -1
- package/lib/commonjs/skia/web/JsiSkSurface.d.ts +2 -1
- package/lib/commonjs/skia/web/JsiSkSurface.js +4 -1
- package/lib/commonjs/skia/web/JsiSkSurface.js.map +1 -1
- package/lib/commonjs/sksg/HostConfig.js +1 -1
- package/lib/commonjs/sksg/HostConfig.js.map +1 -1
- package/lib/commonjs/sksg/Recorder/DrawingContext.d.ts +2 -0
- package/lib/commonjs/sksg/Recorder/DrawingContext.js +14 -2
- package/lib/commonjs/sksg/Recorder/DrawingContext.js.map +1 -1
- package/lib/commonjs/sksg/Recorder/Player.js +6 -2
- package/lib/commonjs/sksg/Recorder/Player.js.map +1 -1
- package/lib/commonjs/sksg/Recorder/commands/Paint.d.ts +3 -2
- package/lib/commonjs/sksg/Recorder/commands/Paint.js +5 -4
- package/lib/commonjs/sksg/Recorder/commands/Paint.js.map +1 -1
- package/lib/commonjs/views/SkiaBaseWebView.js +4 -0
- package/lib/commonjs/views/SkiaBaseWebView.js.map +1 -1
- package/lib/module/skia/types/Image/ImageFactory.d.ts +2 -1
- package/lib/module/skia/types/Image/ImageFactory.js.map +1 -1
- package/lib/module/skia/types/Surface/Surface.d.ts +1 -1
- package/lib/module/skia/types/Surface/Surface.js.map +1 -1
- package/lib/module/skia/web/JsiSkImageFactory.d.ts +1 -0
- package/lib/module/skia/web/JsiSkImageFactory.js +3 -0
- package/lib/module/skia/web/JsiSkImageFactory.js.map +1 -1
- package/lib/module/skia/web/JsiSkSurface.d.ts +2 -1
- package/lib/module/skia/web/JsiSkSurface.js +4 -1
- package/lib/module/skia/web/JsiSkSurface.js.map +1 -1
- package/lib/module/sksg/HostConfig.js +1 -1
- package/lib/module/sksg/HostConfig.js.map +1 -1
- package/lib/module/sksg/Recorder/DrawingContext.d.ts +2 -0
- package/lib/module/sksg/Recorder/DrawingContext.js +14 -2
- package/lib/module/sksg/Recorder/DrawingContext.js.map +1 -1
- package/lib/module/sksg/Recorder/Player.js +6 -2
- package/lib/module/sksg/Recorder/Player.js.map +1 -1
- package/lib/module/sksg/Recorder/commands/Paint.d.ts +3 -2
- package/lib/module/sksg/Recorder/commands/Paint.js +5 -4
- package/lib/module/sksg/Recorder/commands/Paint.js.map +1 -1
- package/lib/module/views/SkiaBaseWebView.js +4 -0
- package/lib/module/views/SkiaBaseWebView.js.map +1 -1
- package/lib/typescript/lib/commonjs/skia/web/JsiSkImageFactory.d.ts +1 -0
- package/lib/typescript/lib/commonjs/skia/web/JsiSkSurface.d.ts +1 -1
- package/lib/typescript/lib/commonjs/sksg/HostConfig.d.ts +1 -1
- package/lib/typescript/lib/commonjs/sksg/Recorder/DrawingContext.d.ts +2 -0
- package/lib/typescript/lib/commonjs/sksg/Recorder/commands/Paint.d.ts +1 -1
- package/lib/typescript/lib/module/skia/web/JsiSkImageFactory.d.ts +1 -0
- package/lib/typescript/lib/module/skia/web/JsiSkSurface.d.ts +1 -1
- package/lib/typescript/lib/module/sksg/HostConfig.d.ts +1 -1
- package/lib/typescript/lib/module/sksg/Recorder/DrawingContext.d.ts +2 -0
- package/lib/typescript/lib/module/sksg/Recorder/commands/Paint.d.ts +1 -1
- package/lib/typescript/src/skia/types/Image/ImageFactory.d.ts +2 -1
- package/lib/typescript/src/skia/types/Surface/Surface.d.ts +1 -1
- package/lib/typescript/src/skia/web/JsiSkImageFactory.d.ts +1 -0
- package/lib/typescript/src/skia/web/JsiSkSurface.d.ts +2 -1
- package/lib/typescript/src/sksg/Recorder/DrawingContext.d.ts +2 -0
- package/lib/typescript/src/sksg/Recorder/commands/Paint.d.ts +3 -2
- package/package.json +1 -1
- package/react-native-skia.podspec +43 -12
- package/src/renderer/__tests__/e2e/DataEncoding.spec.tsx +6 -2
- package/src/renderer/__tests__/e2e/Paint.spec.tsx +44 -1
- package/src/skia/types/Image/ImageFactory.ts +3 -1
- package/src/skia/types/Surface/Surface.ts +1 -1
- package/src/skia/web/JsiSkImageFactory.ts +4 -0
- package/src/skia/web/JsiSkSurface.ts +4 -1
- package/src/sksg/HostConfig.ts +2 -4
- package/src/sksg/Recorder/DrawingContext.ts +15 -1
- package/src/sksg/Recorder/Player.ts +6 -2
- package/src/sksg/Recorder/commands/Paint.ts +6 -5
- package/src/views/SkiaBaseWebView.tsx +4 -0
@@ -4,8 +4,48 @@ require "json"
|
|
4
4
|
|
5
5
|
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
|
6
6
|
|
7
|
-
# Check
|
8
|
-
|
7
|
+
# Check if Graphite symbols are available in libskia
|
8
|
+
libskia_path = File.join(__dir__, "libs/apple/libskia.xcframework")
|
9
|
+
use_graphite = false
|
10
|
+
|
11
|
+
if File.exist?(libskia_path)
|
12
|
+
# Look for any arm64 or x86_64 framework inside the xcframework
|
13
|
+
framework_paths = Dir.glob(File.join(libskia_path, "**/libskia.framework/libskia"))
|
14
|
+
|
15
|
+
# Also try looking for static libraries if frameworks aren't found
|
16
|
+
if framework_paths.empty?
|
17
|
+
framework_paths = Dir.glob(File.join(libskia_path, "**/libskia.a"))
|
18
|
+
end
|
19
|
+
|
20
|
+
framework_paths.each do |framework_path|
|
21
|
+
if File.exist?(framework_path)
|
22
|
+
# Look for specific Dawn function symbols that indicate Graphite support
|
23
|
+
dawn_symbols = [
|
24
|
+
'dawn::',
|
25
|
+
'wgpu',
|
26
|
+
'_ZN4dawn',
|
27
|
+
'DawnDevice',
|
28
|
+
'dawn_native'
|
29
|
+
]
|
30
|
+
|
31
|
+
dawn_symbols.each do |symbol|
|
32
|
+
nm_output = `nm "#{framework_path}" 2>/dev/null | grep "#{symbol}"`
|
33
|
+
if $?.success? && !nm_output.empty?
|
34
|
+
use_graphite = true
|
35
|
+
break
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
break if use_graphite
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
if use_graphite
|
45
|
+
puts "SK_GRAPHITE: ON (Graphite symbols found in libskia)"
|
46
|
+
else
|
47
|
+
puts "SK_GRAPHITE: OFF (Graphite symbols not found in libskia)"
|
48
|
+
end
|
9
49
|
|
10
50
|
# Set preprocessor definitions based on GRAPHITE flag
|
11
51
|
preprocessor_defs = use_graphite ?
|
@@ -20,13 +60,6 @@ base_frameworks = ['libs/apple/libskia.xcframework',
|
|
20
60
|
'libs/apple/libskunicode_core.xcframework',
|
21
61
|
'libs/apple/libskunicode_libgrapheme.xcframework',]
|
22
62
|
|
23
|
-
# Add Graphite frameworks if enabled
|
24
|
-
graphite_frameworks = [
|
25
|
-
'libs/apple/libdawn_native_static.xcframework',
|
26
|
-
'libs/apple/libdawn_platform_static.xcframework',
|
27
|
-
'libs/apple/libdawn_proc_static.xcframework'
|
28
|
-
]
|
29
|
-
|
30
63
|
Pod::Spec.new do |s|
|
31
64
|
s.name = "react-native-skia"
|
32
65
|
s.version = package["version"]
|
@@ -54,9 +87,7 @@ Pod::Spec.new do |s|
|
|
54
87
|
|
55
88
|
s.frameworks = ['MetalKit', 'AVFoundation', 'AVKit', 'CoreMedia']
|
56
89
|
|
57
|
-
s.vendored_frameworks =
|
58
|
-
base_frameworks + graphite_frameworks :
|
59
|
-
base_frameworks
|
90
|
+
s.vendored_frameworks = base_frameworks
|
60
91
|
|
61
92
|
# All iOS cpp/h files
|
62
93
|
s.source_files = [
|
@@ -52,7 +52,9 @@ describe("Data Encoding", () => {
|
|
52
52
|
const offscreen = Skia.Surface.MakeOffscreen(1, 1)!;
|
53
53
|
const canvas = offscreen.getCanvas();
|
54
54
|
canvas.drawImage(img, 0, 0);
|
55
|
-
|
55
|
+
const snapshotImage = Skia.Image.MakeNull();
|
56
|
+
offscreen.makeImageSnapshot(undefined, snapshotImage);
|
57
|
+
return Array.from(snapshotImage.encodeToBytes());
|
56
58
|
});
|
57
59
|
expect(result.length).toBeGreaterThan(0);
|
58
60
|
});
|
@@ -68,7 +70,9 @@ describe("Data Encoding", () => {
|
|
68
70
|
const offscreen = Skia.Surface.MakeOffscreen(1, 1)!;
|
69
71
|
const canvas = offscreen.getCanvas();
|
70
72
|
canvas.drawImage(img, 0, 0);
|
71
|
-
|
73
|
+
const snapshotImage = Skia.Image.MakeNull();
|
74
|
+
offscreen.makeImageSnapshot(undefined, snapshotImage);
|
75
|
+
return snapshotImage.encodeToBase64();
|
72
76
|
});
|
73
77
|
expect(result.length).toBeGreaterThan(0);
|
74
78
|
});
|
@@ -10,7 +10,7 @@ import {
|
|
10
10
|
Paint,
|
11
11
|
Path,
|
12
12
|
} from "../../components";
|
13
|
-
import { checkImage } from "../../../__tests__/setup";
|
13
|
+
import { checkImage, docPath } from "../../../__tests__/setup";
|
14
14
|
import { fitbox } from "../../components/shapes/FitBox";
|
15
15
|
|
16
16
|
const blendModes = [
|
@@ -167,4 +167,47 @@ describe("Paint", () => {
|
|
167
167
|
threshold: 0,
|
168
168
|
});
|
169
169
|
});
|
170
|
+
it("should override colors", async () => {
|
171
|
+
const { vec } = importSkia();
|
172
|
+
const strokeWidth = 10;
|
173
|
+
const { width, height } = surface;
|
174
|
+
const c = vec(width / 2, height / 2);
|
175
|
+
const r = (width - strokeWidth) / 2;
|
176
|
+
const result = await surface.draw(
|
177
|
+
<>
|
178
|
+
<Circle c={c} r={r} color="transparent">
|
179
|
+
<Paint color="lightblue" />
|
180
|
+
<Paint color="#adbce6" style="stroke" strokeWidth={strokeWidth} />
|
181
|
+
<Paint color="#ade6d8" style="stroke" strokeWidth={strokeWidth / 2} />
|
182
|
+
</Circle>
|
183
|
+
</>
|
184
|
+
);
|
185
|
+
checkImage(result, docPath("paint/stroke.png"));
|
186
|
+
});
|
187
|
+
it("colors don't influence opacity (1)", async () => {
|
188
|
+
const { vec } = importSkia();
|
189
|
+
const strokeWidth = 10;
|
190
|
+
const { width, height } = surface;
|
191
|
+
const c = vec(width / 2, height / 2);
|
192
|
+
const r = (width - strokeWidth) / 2;
|
193
|
+
const result = await surface.draw(
|
194
|
+
<Group color="rgba(0,0,0,0.5)">
|
195
|
+
<Circle c={c} r={r} color="lightblue" />
|
196
|
+
</Group>
|
197
|
+
);
|
198
|
+
checkImage(result, docPath("paint/opaque-circle.png"));
|
199
|
+
});
|
200
|
+
it("colors don't influence opacity (2)", async () => {
|
201
|
+
const { vec } = importSkia();
|
202
|
+
const strokeWidth = 10;
|
203
|
+
const { width, height } = surface;
|
204
|
+
const c = vec(width / 2, height / 2);
|
205
|
+
const r = (width - strokeWidth) / 2;
|
206
|
+
const result = await surface.draw(
|
207
|
+
<Group opacity={0.5}>
|
208
|
+
<Circle c={c} r={r} color="lightblue" />
|
209
|
+
</Group>
|
210
|
+
);
|
211
|
+
checkImage(result, docPath("paint/semi-transparent-circle.png"));
|
212
|
+
});
|
170
213
|
});
|
@@ -21,6 +21,7 @@ export interface ImageInfo {
|
|
21
21
|
}
|
22
22
|
|
23
23
|
export interface ImageFactory {
|
24
|
+
MakeNull: () => SkImage;
|
24
25
|
/**
|
25
26
|
* Return an Image backed by the encoded data, but attempt to defer decoding until the image
|
26
27
|
* is actually used/drawn. This deferral allows the system to cache the result, either on the
|
@@ -70,7 +71,8 @@ export interface ImageFactory {
|
|
70
71
|
texture: unknown,
|
71
72
|
width: number,
|
72
73
|
height: number,
|
73
|
-
mipmapped?: boolean
|
74
|
+
mipmapped?: boolean,
|
75
|
+
outputImage?: SkImage
|
74
76
|
) => SkImage;
|
75
77
|
|
76
78
|
/**
|
@@ -35,7 +35,7 @@ export interface SkSurface extends SkJSIInstance<"Surface"> {
|
|
35
35
|
|
36
36
|
example: https://fiddle.skia.org/c/@Surface_makeImageSnapshot
|
37
37
|
*/
|
38
|
-
makeImageSnapshot(bounds?: SkRect): SkImage;
|
38
|
+
makeImageSnapshot(bounds?: SkRect, outputImage?: SkImage): SkImage;
|
39
39
|
|
40
40
|
/**
|
41
41
|
* Make sure any queued draws are sent to the screen or the GPU.
|
@@ -20,6 +20,10 @@ export class JsiSkImageFactory extends Host implements ImageFactory {
|
|
20
20
|
super(CanvasKit);
|
21
21
|
}
|
22
22
|
|
23
|
+
MakeNull() {
|
24
|
+
return new JsiSkImage(this.CanvasKit, null as unknown as Image);
|
25
|
+
}
|
26
|
+
|
23
27
|
MakeImageFromViewTag(viewTag: number): Promise<SkImage | null> {
|
24
28
|
const view = viewTag as unknown as HTMLElement;
|
25
29
|
// TODO: Implement screenshot from view in React JS
|
@@ -35,12 +35,15 @@ export class JsiSkSurface
|
|
35
35
|
return new JsiSkCanvas(this.CanvasKit, this.ref.getCanvas());
|
36
36
|
}
|
37
37
|
|
38
|
-
makeImageSnapshot(bounds?: SkRect): SkImage {
|
38
|
+
makeImageSnapshot(bounds?: SkRect, outputImage?: JsiSkImage): SkImage {
|
39
39
|
const image = this.ref.makeImageSnapshot(
|
40
40
|
bounds
|
41
41
|
? Array.from(JsiSkRect.fromValue(this.CanvasKit, bounds))
|
42
42
|
: undefined
|
43
43
|
);
|
44
|
+
if (outputImage) {
|
45
|
+
outputImage.ref = image;
|
46
|
+
}
|
44
47
|
return new JsiSkImage(this.CanvasKit, image);
|
45
48
|
}
|
46
49
|
|
package/src/sksg/HostConfig.ts
CHANGED
@@ -177,10 +177,8 @@ export const sksgHostConfig: SkiaHostConfig = {
|
|
177
177
|
_type,
|
178
178
|
_oldProps,
|
179
179
|
newProps,
|
180
|
-
|
181
|
-
|
182
|
-
keepChildren: boolean,
|
183
|
-
_recyclableInstance: null | Instance
|
180
|
+
keepChildren,
|
181
|
+
_newChildSet
|
184
182
|
) {
|
185
183
|
debug("cloneInstance");
|
186
184
|
return {
|
@@ -22,12 +22,14 @@ export const createDrawingContext = (
|
|
22
22
|
const imageFilters: SkImageFilter[] = [];
|
23
23
|
const pathEffects: SkPathEffect[] = [];
|
24
24
|
const paintDeclarations: SkPaint[] = [];
|
25
|
+
const opacities: number[] = [];
|
25
26
|
|
26
27
|
let nextPaintIndex = 1;
|
27
28
|
|
28
|
-
// Initialize first paint
|
29
|
+
// Initialize first paint and opacity
|
29
30
|
paintPool[0] = Skia.Paint();
|
30
31
|
paints.push(paintPool[0]);
|
32
|
+
opacities.push(1);
|
31
33
|
|
32
34
|
// Methods (formerly class methods)
|
33
35
|
const savePaint = () => {
|
@@ -39,9 +41,18 @@ export const createDrawingContext = (
|
|
39
41
|
const nextPaint = paintPool[nextPaintIndex];
|
40
42
|
nextPaint.assign(getCurrentPaint()); // Reuse allocation by copying properties
|
41
43
|
paints.push(nextPaint);
|
44
|
+
opacities.push(opacities[opacities.length - 1]);
|
42
45
|
nextPaintIndex++;
|
43
46
|
};
|
44
47
|
|
48
|
+
const getOpacity = () => {
|
49
|
+
return opacities[opacities.length - 1];
|
50
|
+
};
|
51
|
+
|
52
|
+
const setOpacity = (newOpacity: number) => {
|
53
|
+
opacities[opacities.length - 1] = Math.max(0, Math.min(1, newOpacity));
|
54
|
+
};
|
55
|
+
|
45
56
|
const saveBackdropFilter = () => {
|
46
57
|
let imageFilter: SkImageFilter | null = null;
|
47
58
|
const imgf = imageFilters.pop();
|
@@ -63,6 +74,7 @@ export const createDrawingContext = (
|
|
63
74
|
};
|
64
75
|
|
65
76
|
const restorePaint = () => {
|
77
|
+
opacities.pop();
|
66
78
|
return paints.pop();
|
67
79
|
};
|
68
80
|
|
@@ -125,6 +137,8 @@ export const createDrawingContext = (
|
|
125
137
|
}, // the "getter" for the current paint
|
126
138
|
restorePaint,
|
127
139
|
materializePaint,
|
140
|
+
getOpacity,
|
141
|
+
setOpacity,
|
128
142
|
};
|
129
143
|
};
|
130
144
|
|
@@ -67,7 +67,7 @@ function play(ctx: DrawingContext, _command: Command) {
|
|
67
67
|
ctx.paints.push(command.props.paint);
|
68
68
|
} else {
|
69
69
|
ctx.savePaint();
|
70
|
-
setPaintProperties(ctx.Skia, ctx
|
70
|
+
setPaintProperties(ctx.Skia, ctx, command.props);
|
71
71
|
}
|
72
72
|
} else if (isCommand(command, CommandType.RestorePaint)) {
|
73
73
|
ctx.restorePaint();
|
@@ -101,7 +101,11 @@ function play(ctx: DrawingContext, _command: Command) {
|
|
101
101
|
} else if (isCommand(command, CommandType.RestoreCTM)) {
|
102
102
|
ctx.canvas.restore();
|
103
103
|
} else {
|
104
|
-
|
104
|
+
// TODO: is a copy needed here?
|
105
|
+
// apply opacity to the current paint.
|
106
|
+
const paint = ctx.paint.copy();
|
107
|
+
paint.setAlphaf(paint.getAlphaf() * ctx.getOpacity());
|
108
|
+
const paints = [paint, ...ctx.paintDeclarations];
|
105
109
|
ctx.paintDeclarations = [];
|
106
110
|
paints.forEach((p) => {
|
107
111
|
ctx.paints.push(p);
|
@@ -6,11 +6,12 @@ import {
|
|
6
6
|
StrokeCap,
|
7
7
|
StrokeJoin,
|
8
8
|
} from "../../../skia/types";
|
9
|
-
import type {
|
9
|
+
import type { Skia } from "../../../skia/types";
|
10
|
+
import type { DrawingContext } from "../DrawingContext";
|
10
11
|
|
11
12
|
export const setPaintProperties = (
|
12
13
|
Skia: Skia,
|
13
|
-
|
14
|
+
ctx: DrawingContext,
|
14
15
|
{
|
15
16
|
opacity,
|
16
17
|
color,
|
@@ -25,14 +26,14 @@ export const setPaintProperties = (
|
|
25
26
|
}: PaintProps
|
26
27
|
) => {
|
27
28
|
"worklet";
|
29
|
+
const { paint } = ctx;
|
30
|
+
|
28
31
|
if (opacity !== undefined) {
|
29
|
-
|
32
|
+
ctx.setOpacity(ctx.getOpacity() * opacity);
|
30
33
|
}
|
31
34
|
if (color !== undefined) {
|
32
|
-
const currentOpacity = paint.getAlphaf();
|
33
35
|
paint.setShader(null);
|
34
36
|
paint.setColor(processColor(Skia, color));
|
35
|
-
paint.setAlphaf(currentOpacity * paint.getAlphaf());
|
36
37
|
}
|
37
38
|
if (blendMode !== undefined) {
|
38
39
|
paint.setBlendMode(BlendMode[enumKey(blendMode)]);
|
@@ -42,6 +42,10 @@ export abstract class SkiaBaseWebView<
|
|
42
42
|
canvas.width = this.width * pd;
|
43
43
|
canvas.height = this.height * pd;
|
44
44
|
const surface = CanvasKit.MakeWebGLCanvasSurface(canvas);
|
45
|
+
const ctx = canvas.getContext("webgl2");
|
46
|
+
if (ctx) {
|
47
|
+
ctx.drawingBufferColorSpace = "display-p3";
|
48
|
+
}
|
45
49
|
if (!surface) {
|
46
50
|
throw new Error("Could not create surface");
|
47
51
|
}
|