@shopify/react-native-skia 2.3.14 → 2.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/cpp/api/JsiSkPictureFactory.h +24 -6
  2. package/cpp/api/recorder/Command.h +12 -0
  3. package/cpp/api/recorder/JsiRecorder.h +2 -1
  4. package/cpp/api/recorder/RNRecorder.h +434 -374
  5. package/lib/commonjs/dom/types/Common.d.ts +1 -0
  6. package/lib/commonjs/dom/types/Common.js.map +1 -1
  7. package/lib/commonjs/skia/types/Recorder.d.ts +2 -2
  8. package/lib/commonjs/skia/types/Recorder.js.map +1 -1
  9. package/lib/commonjs/sksg/Recorder/Core.d.ts +2 -1
  10. package/lib/commonjs/sksg/Recorder/Core.js +0 -42
  11. package/lib/commonjs/sksg/Recorder/Core.js.map +1 -1
  12. package/lib/commonjs/sksg/Recorder/Debug.d.ts +2 -0
  13. package/lib/commonjs/sksg/Recorder/Debug.js +86 -0
  14. package/lib/commonjs/sksg/Recorder/Debug.js.map +1 -0
  15. package/lib/commonjs/sksg/Recorder/Player.d.ts +1 -1
  16. package/lib/commonjs/sksg/Recorder/Player.js +51 -7
  17. package/lib/commonjs/sksg/Recorder/Player.js.map +1 -1
  18. package/lib/commonjs/sksg/Recorder/ReanimatedRecorder.d.ts +2 -2
  19. package/lib/commonjs/sksg/Recorder/ReanimatedRecorder.js +7 -2
  20. package/lib/commonjs/sksg/Recorder/ReanimatedRecorder.js.map +1 -1
  21. package/lib/commonjs/sksg/Recorder/Recorder.d.ts +2 -2
  22. package/lib/commonjs/sksg/Recorder/Recorder.js +7 -3
  23. package/lib/commonjs/sksg/Recorder/Recorder.js.map +1 -1
  24. package/lib/commonjs/sksg/Recorder/Visitor.js +14 -6
  25. package/lib/commonjs/sksg/Recorder/Visitor.js.map +1 -1
  26. package/lib/commonjs/views/SkiaPictureView.js.map +1 -1
  27. package/lib/module/dom/types/Common.d.ts +1 -0
  28. package/lib/module/dom/types/Common.js.map +1 -1
  29. package/lib/module/skia/types/Recorder.d.ts +2 -2
  30. package/lib/module/skia/types/Recorder.js.map +1 -1
  31. package/lib/module/sksg/Recorder/Core.d.ts +2 -1
  32. package/lib/module/sksg/Recorder/Core.js +0 -42
  33. package/lib/module/sksg/Recorder/Core.js.map +1 -1
  34. package/lib/module/sksg/Recorder/Debug.d.ts +2 -0
  35. package/lib/module/sksg/Recorder/Debug.js +79 -0
  36. package/lib/module/sksg/Recorder/Debug.js.map +1 -0
  37. package/lib/module/sksg/Recorder/Player.d.ts +1 -1
  38. package/lib/module/sksg/Recorder/Player.js +50 -5
  39. package/lib/module/sksg/Recorder/Player.js.map +1 -1
  40. package/lib/module/sksg/Recorder/ReanimatedRecorder.d.ts +2 -2
  41. package/lib/module/sksg/Recorder/ReanimatedRecorder.js +7 -2
  42. package/lib/module/sksg/Recorder/ReanimatedRecorder.js.map +1 -1
  43. package/lib/module/sksg/Recorder/Recorder.d.ts +2 -2
  44. package/lib/module/sksg/Recorder/Recorder.js +7 -3
  45. package/lib/module/sksg/Recorder/Recorder.js.map +1 -1
  46. package/lib/module/sksg/Recorder/Visitor.js +14 -6
  47. package/lib/module/sksg/Recorder/Visitor.js.map +1 -1
  48. package/lib/module/views/SkiaPictureView.js.map +1 -1
  49. package/lib/typescript/lib/commonjs/sksg/Recorder/Debug.d.ts +2 -0
  50. package/lib/typescript/lib/commonjs/sksg/Recorder/ReanimatedRecorder.d.ts +1 -1
  51. package/lib/typescript/lib/commonjs/sksg/Recorder/Recorder.d.ts +1 -1
  52. package/lib/typescript/lib/module/sksg/Recorder/Debug.d.ts +1 -0
  53. package/lib/typescript/lib/module/sksg/Recorder/ReanimatedRecorder.d.ts +1 -1
  54. package/lib/typescript/lib/module/sksg/Recorder/Recorder.d.ts +1 -1
  55. package/lib/typescript/src/dom/types/Common.d.ts +1 -0
  56. package/lib/typescript/src/skia/types/Recorder.d.ts +2 -2
  57. package/lib/typescript/src/sksg/Recorder/Core.d.ts +2 -1
  58. package/lib/typescript/src/sksg/Recorder/Debug.d.ts +2 -0
  59. package/lib/typescript/src/sksg/Recorder/Player.d.ts +1 -1
  60. package/lib/typescript/src/sksg/Recorder/ReanimatedRecorder.d.ts +2 -2
  61. package/lib/typescript/src/sksg/Recorder/Recorder.d.ts +2 -2
  62. package/package.json +1 -1
  63. package/src/dom/types/Common.ts +3 -1
  64. package/src/skia/types/Recorder.ts +2 -1
  65. package/src/sksg/Recorder/Core.ts +2 -43
  66. package/src/sksg/Recorder/Debug.ts +87 -0
  67. package/src/sksg/Recorder/Player.ts +62 -7
  68. package/src/sksg/Recorder/ReanimatedRecorder.ts +8 -2
  69. package/src/sksg/Recorder/Recorder.ts +7 -2
  70. package/src/sksg/Recorder/Visitor.ts +18 -6
  71. package/src/views/SkiaPictureView.tsx +7 -1
@@ -1,6 +1,6 @@
1
1
  import type { SharedValue } from "react-native-reanimated";
2
2
  import { NodeType } from "../../dom/types";
3
- import type { BlurMaskFilterProps, CircleProps, CTMProps, ImageProps, PaintProps, PointsProps, PathProps, RectProps, RoundedRectProps, OvalProps, LineProps, PatchProps, VerticesProps, DiffRectProps, TextProps, TextPathProps, TextBlobProps, GlyphsProps, PictureProps, ImageSVGProps, ParagraphProps, AtlasProps, BoxProps, BoxShadowProps, SkottieProps } from "../../dom/types";
3
+ import type { BlurMaskFilterProps, CircleProps, CTMProps, ImageProps, PaintProps, PointsProps, PathProps, RectProps, RoundedRectProps, OvalProps, LineProps, PatchProps, VerticesProps, DiffRectProps, TextProps, TextPathProps, TextBlobProps, GlyphsProps, PictureProps, ImageSVGProps, ParagraphProps, AtlasProps, BoxProps, BoxShadowProps, SkottieProps, DrawingNodeProps } from "../../dom/types";
4
4
  import type { AnimatedProps } from "../../renderer";
5
5
  import type { SkPaint, BaseRecorder } from "../../skia/types";
6
6
  import type { Command } from "./Core";
@@ -19,7 +19,7 @@ export declare class Recorder implements BaseRecorder {
19
19
  getRecording(): Recording & AnimationValues;
20
20
  private processProps;
21
21
  private add;
22
- saveGroup(): void;
22
+ saveGroup(props?: AnimatedProps<Pick<DrawingNodeProps, "zIndex">>): void;
23
23
  restoreGroup(): void;
24
24
  savePaint(props: AnimatedProps<PaintProps>, standalone: boolean): void;
25
25
  restorePaint(): void;
package/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "setup-skia-web": "scripts/setup-canvaskit.js"
9
9
  },
10
10
  "title": "React Native Skia",
11
- "version": "2.3.14",
11
+ "version": "2.4.1",
12
12
  "skia": {
13
13
  "version": "m142",
14
14
  "checksums": {
@@ -89,4 +89,6 @@ export interface PaintProps extends ChildrenProps {
89
89
  dither?: boolean;
90
90
  }
91
91
 
92
- export interface GroupProps extends PaintProps, CTMProps {}
92
+ export interface GroupProps extends PaintProps, CTMProps {
93
+ zIndex?: number;
94
+ }
@@ -27,13 +27,14 @@ import type {
27
27
  TextPathProps,
28
28
  VerticesProps,
29
29
  SkottieProps,
30
+ DrawingNodeProps,
30
31
  } from "../../dom/types";
31
32
  import type { AnimatedProps } from "../../renderer/processors/Animations/Animations";
32
33
 
33
34
  import type { SkPicture } from "./Picture";
34
35
 
35
36
  export interface BaseRecorder {
36
- saveGroup(): void;
37
+ saveGroup(props?: AnimatedProps<Pick<DrawingNodeProps, "zIndex">>): void;
37
38
  restoreGroup(): void;
38
39
  savePaint(props: AnimatedProps<PaintProps>, standalone: boolean): void;
39
40
  restorePaint(): void;
@@ -24,48 +24,6 @@ import type {
24
24
  SkottieProps,
25
25
  } from "../../dom/types";
26
26
 
27
- // export enum CommandType {
28
- // // Context
29
- // Group = "Group",
30
- // SavePaint = "SavePaint",
31
- // RestorePaint = "RestorePaint",
32
- // SaveCTM = "SaveCTM",
33
- // RestoreCTM = "RestoreCTM",
34
- // PushColorFilter = "PushColorFilter",
35
- // PushBlurMaskFilter = "PushBlurMaskFilter",
36
- // PushImageFilter = "PushImageFilter",
37
- // PushPathEffect = "PushPathEffect",
38
- // PushShader = "PushShader",
39
- // ComposeColorFilter = "ComposeColorFilter",
40
- // ComposeImageFilter = "ComposeImageFilter",
41
- // ComposePathEffect = "ComposePathEffect",
42
- // MaterializePaint = "MaterializePaint",
43
- // SaveBackdropFilter = "SaveBackdropFilter",
44
- // SaveLayer = "SaveLayer",
45
- // RestorePaintDeclaration = "RestorePaintDeclaration",
46
- // // Drawing
47
- // DrawBox = "DrawBox",
48
- // DrawImage = "DrawImage",
49
- // DrawCircle = "DrawCircle",
50
- // DrawPaint = "DrawPaint",
51
- // DrawPoints = "DrawPoints",
52
- // DrawPath = "DrawPath",
53
- // DrawRect = "DrawRect",
54
- // DrawRRect = "DrawRRect",
55
- // DrawOval = "DrawOval",
56
- // DrawLine = "DrawLine",
57
- // DrawPatch = "DrawPatch",
58
- // DrawVertices = "DrawVertices",
59
- // DrawDiffRect = "DrawDiffRect",
60
- // DrawText = "DrawText",
61
- // DrawTextPath = "DrawTextPath",
62
- // DrawTextBlob = "DrawTextBlob",
63
- // DrawGlyphs = "DrawGlyphs",
64
- // DrawPicture = "DrawPicture",
65
- // DrawImageSVG = "DrawImageSVG",
66
- // DrawParagraph = "DrawParagraph",
67
- // DrawAtlas = "DrawAtlas",
68
- // }
69
27
  export enum CommandType {
70
28
  // Context
71
29
  Group,
@@ -135,7 +93,8 @@ export const isCommand = <T extends CommandType>(
135
93
  return command.type === type;
136
94
  };
137
95
 
138
- interface GroupCommand extends Command<CommandType.Group> {
96
+ export interface GroupCommand extends Command<CommandType.Group> {
97
+ props?: Pick<DrawingNodeProps, "zIndex">;
139
98
  children: Command[];
140
99
  }
141
100
 
@@ -0,0 +1,87 @@
1
+ import { CommandType, isGroup } from "./Core";
2
+ import type { Command } from "./Core";
3
+
4
+ const CommandTypeNames: Record<CommandType, string> = {
5
+ [CommandType.Group]: "Group",
6
+ [CommandType.SavePaint]: "SavePaint",
7
+ [CommandType.RestorePaint]: "RestorePaint",
8
+ [CommandType.SaveCTM]: "SaveCTM",
9
+ [CommandType.RestoreCTM]: "RestoreCTM",
10
+ [CommandType.PushColorFilter]: "PushColorFilter",
11
+ [CommandType.PushBlurMaskFilter]: "PushBlurMaskFilter",
12
+ [CommandType.PushImageFilter]: "PushImageFilter",
13
+ [CommandType.PushPathEffect]: "PushPathEffect",
14
+ [CommandType.PushShader]: "PushShader",
15
+ [CommandType.ComposeColorFilter]: "ComposeColorFilter",
16
+ [CommandType.ComposeImageFilter]: "ComposeImageFilter",
17
+ [CommandType.ComposePathEffect]: "ComposePathEffect",
18
+ [CommandType.MaterializePaint]: "MaterializePaint",
19
+ [CommandType.SaveBackdropFilter]: "SaveBackdropFilter",
20
+ [CommandType.SaveLayer]: "SaveLayer",
21
+ [CommandType.RestorePaintDeclaration]: "RestorePaintDeclaration",
22
+ [CommandType.DrawBox]: "DrawBox",
23
+ [CommandType.DrawImage]: "DrawImage",
24
+ [CommandType.DrawCircle]: "DrawCircle",
25
+ [CommandType.DrawPaint]: "DrawPaint",
26
+ [CommandType.DrawPoints]: "DrawPoints",
27
+ [CommandType.DrawPath]: "DrawPath",
28
+ [CommandType.DrawRect]: "DrawRect",
29
+ [CommandType.DrawRRect]: "DrawRRect",
30
+ [CommandType.DrawOval]: "DrawOval",
31
+ [CommandType.DrawLine]: "DrawLine",
32
+ [CommandType.DrawPatch]: "DrawPatch",
33
+ [CommandType.DrawVertices]: "DrawVertices",
34
+ [CommandType.DrawDiffRect]: "DrawDiffRect",
35
+ [CommandType.DrawText]: "DrawText",
36
+ [CommandType.DrawTextPath]: "DrawTextPath",
37
+ [CommandType.DrawTextBlob]: "DrawTextBlob",
38
+ [CommandType.DrawGlyphs]: "DrawGlyphs",
39
+ [CommandType.DrawPicture]: "DrawPicture",
40
+ [CommandType.DrawImageSVG]: "DrawImageSVG",
41
+ [CommandType.DrawParagraph]: "DrawParagraph",
42
+ [CommandType.DrawAtlas]: "DrawAtlas",
43
+ [CommandType.DrawSkottie]: "DrawSkottie",
44
+ };
45
+
46
+ const serializeProps = (props: unknown): string => {
47
+ try {
48
+ return JSON.stringify(props, (key, value) => {
49
+ if (key === "children") {
50
+ return undefined;
51
+ }
52
+ if (typeof value === "bigint") {
53
+ return value.toString();
54
+ }
55
+ return value;
56
+ });
57
+ } catch (e) {
58
+ return `"Error serializing props: ${e}"`;
59
+ }
60
+ };
61
+
62
+ export const debugTree = (commands: Command[], indent = 0): string => {
63
+ let result = "[\n";
64
+ const prefix = " ".repeat(indent + 2);
65
+
66
+ commands.forEach((cmd, index) => {
67
+ const type = CommandTypeNames[cmd.type] || "Unknown";
68
+ result += `${prefix}{ "type": "${type}"`;
69
+
70
+ if ("props" in cmd) {
71
+ result += `, "props": ${serializeProps(cmd.props)}`;
72
+ }
73
+
74
+ if (isGroup(cmd)) {
75
+ result += `, "children": ${debugTree(cmd.children, indent + 2)}`;
76
+ }
77
+
78
+ result += " }";
79
+ if (index < commands.length - 1) {
80
+ result += ",";
81
+ }
82
+ result += "\n";
83
+ });
84
+
85
+ result += " ".repeat(indent) + "]";
86
+ return result;
87
+ };
@@ -1,3 +1,5 @@
1
+ import type { DrawingNodeProps } from "../../dom/types";
2
+
1
3
  import {
2
4
  drawCircle,
3
5
  drawImage,
@@ -47,13 +49,66 @@ import {
47
49
  isGroup,
48
50
  materializeCommand,
49
51
  } from "./Core";
50
- import type { Command } from "./Core";
52
+ import type { Command, GroupCommand } from "./Core";
51
53
  import type { DrawingContext } from "./DrawingContext";
52
54
 
53
- function play(ctx: DrawingContext, _command: Command) {
55
+ type PendingGroup = {
56
+ command: GroupCommand;
57
+ zIndex: number;
58
+ order: number;
59
+ };
60
+
61
+ const getZIndex = (command: GroupCommand) => {
62
+ "worklet";
63
+ const materialized = materializeCommand(command);
64
+ const { zIndex } = (materialized.props ?? {}) as DrawingNodeProps;
65
+ if (typeof zIndex !== "number" || Number.isNaN(zIndex)) {
66
+ return 0;
67
+ }
68
+ return zIndex;
69
+ };
70
+
71
+ const flushPendingGroups = (
72
+ ctx: DrawingContext,
73
+ pendingGroups: PendingGroup[]
74
+ ) => {
54
75
  "worklet";
76
+ if (pendingGroups.length === 0) {
77
+ return;
78
+ }
79
+ pendingGroups
80
+ .sort((a, b) =>
81
+ a.zIndex === b.zIndex ? a.order - b.order : a.zIndex - b.zIndex
82
+ )
83
+ .forEach(({ command }) => {
84
+ play(ctx, command);
85
+ });
86
+ pendingGroups.length = 0;
87
+ };
88
+
89
+ const play = (ctx: DrawingContext, _command: Command) => {
90
+ // eslint-disable-next-line @typescript-eslint/no-shadow
91
+ const playGroup = (ctx: DrawingContext, group: GroupCommand) => {
92
+ "worklet";
93
+ const pending: PendingGroup[] = [];
94
+ group.children.forEach((child) => {
95
+ if (isGroup(child)) {
96
+ pending.push({
97
+ command: child,
98
+ zIndex: getZIndex(child),
99
+ order: pending.length,
100
+ });
101
+ return;
102
+ }
103
+ flushPendingGroups(ctx, pending);
104
+ play(ctx, child);
105
+ });
106
+ flushPendingGroups(ctx, pending);
107
+ };
108
+
109
+ ("worklet");
55
110
  if (isGroup(_command)) {
56
- _command.children.forEach((child) => play(ctx, child));
111
+ playGroup(ctx, _command);
57
112
  return;
58
113
  }
59
114
  const command = materializeCommand(_command);
@@ -166,11 +221,11 @@ function play(ctx: DrawingContext, _command: Command) {
166
221
  ctx.paints.pop();
167
222
  });
168
223
  }
169
- }
170
-
171
- export const replay = (ctx: DrawingContext, commands: Command[]) => {
224
+ };
225
+ export function replay(ctx: DrawingContext, commands: Command[]) {
172
226
  "worklet";
227
+ //console.log(debugTree(commands));
173
228
  commands.forEach((command) => {
174
229
  play(ctx, command);
175
230
  });
176
- };
231
+ }
@@ -28,6 +28,7 @@ import type {
28
28
  ParagraphProps,
29
29
  AtlasProps,
30
30
  SkottieProps,
31
+ DrawingNodeProps,
31
32
  } from "../../dom/types";
32
33
  import type { AnimatedProps } from "../../renderer";
33
34
  import { isSharedValue } from "../utils";
@@ -71,8 +72,13 @@ export class ReanimatedRecorder implements BaseRecorder {
71
72
  return Array.from(this.values);
72
73
  }
73
74
 
74
- saveGroup(): void {
75
- this.recorder.saveGroup();
75
+ saveGroup(props?: AnimatedProps<Pick<DrawingNodeProps, "zIndex">>): void {
76
+ if (props) {
77
+ this.processAnimationValues(props);
78
+ this.recorder.saveGroup(props);
79
+ } else {
80
+ this.recorder.saveGroup();
81
+ }
76
82
  }
77
83
 
78
84
  restoreGroup(): void {
@@ -27,6 +27,7 @@ import type {
27
27
  BoxProps,
28
28
  BoxShadowProps,
29
29
  SkottieProps,
30
+ DrawingNodeProps,
30
31
  } from "../../dom/types";
31
32
  import type { AnimatedProps } from "../../renderer";
32
33
  import { isSharedValue } from "../utils";
@@ -93,9 +94,13 @@ export class Recorder implements BaseRecorder {
93
94
  this.cursors[this.cursors.length - 1].push(command);
94
95
  }
95
96
 
96
- saveGroup() {
97
+ saveGroup(props?: AnimatedProps<Pick<DrawingNodeProps, "zIndex">>) {
97
98
  const children: Command[] = [];
98
- this.add({ type: CommandType.Group, children });
99
+ const group: Command = { type: CommandType.Group, children };
100
+ if (props) {
101
+ group.props = props;
102
+ }
103
+ this.add(group);
99
104
  this.cursors.push(children);
100
105
  }
101
106
 
@@ -8,6 +8,7 @@ import { NodeType } from "../../dom/types";
8
8
  import type { BaseRecorder } from "../../skia/types/Recorder";
9
9
  import type { Node } from "../Node";
10
10
  import { isImageFilter, isShader, sortNodeChildren } from "../Node";
11
+ import type { AnimatedProps } from "../../renderer";
11
12
 
12
13
  export const processPaint = ({
13
14
  opacity,
@@ -200,11 +201,24 @@ const pushPaints = (recorder: BaseRecorder, paints: Node<any>[]) => {
200
201
  });
201
202
  };
202
203
 
203
- const visitNode = (recorder: BaseRecorder, node: Node<any>) => {
204
- if (node.type === NodeType.Group) {
205
- recorder.saveGroup();
204
+ type StackingContextProps = Pick<DrawingNodeProps, "zIndex">;
205
+
206
+ const getStackingContextProps = (
207
+ props: AnimatedProps<DrawingNodeProps>
208
+ ): AnimatedProps<StackingContextProps> | undefined => {
209
+ const { zIndex } = props;
210
+ if (zIndex === undefined) {
211
+ return undefined;
206
212
  }
213
+ return { zIndex };
214
+ };
215
+
216
+ const visitNode = (recorder: BaseRecorder, node: Node<any>) => {
207
217
  const { props } = node;
218
+ const stackingContextProps = getStackingContextProps(
219
+ props as AnimatedProps<DrawingNodeProps>
220
+ );
221
+ recorder.saveGroup(stackingContextProps);
208
222
  const {
209
223
  colorFilters,
210
224
  maskFilters,
@@ -326,9 +340,7 @@ const visitNode = (recorder: BaseRecorder, node: Node<any>) => {
326
340
  if (shouldRestore) {
327
341
  recorder.restoreCTM();
328
342
  }
329
- if (node.type === NodeType.Group) {
330
- recorder.restoreGroup();
331
- }
343
+ recorder.restoreGroup();
332
344
  };
333
345
 
334
346
  export const visit = (recorder: BaseRecorder, root: Node[]) => {
@@ -83,7 +83,13 @@ export class SkiaPictureView extends React.Component<SkiaPictureViewProps> {
83
83
  }
84
84
 
85
85
  render() {
86
- const { mode, debug = false, opaque = false, coldStart = false, ...viewProps } = this.props;
86
+ const {
87
+ mode,
88
+ debug = false,
89
+ opaque = false,
90
+ coldStart = false,
91
+ ...viewProps
92
+ } = this.props;
87
93
  return (
88
94
  <NativeSkiaPictureView
89
95
  collapsable={false}