@shopify/react-native-skia 1.8.2 → 1.9.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (198) hide show
  1. package/android/cpp/rnskia-android/MainThreadDispatcher.h +1 -1
  2. package/android/cpp/rnskia-android/OpenGLContext.h +4 -4
  3. package/android/cpp/rnskia-android/RNSkOpenGLCanvasProvider.cpp +3 -3
  4. package/cpp/api/JsiSkCanvas.h +27 -25
  5. package/cpp/api/JsiSkImage.h +24 -0
  6. package/cpp/api/JsiSkPaint.h +1 -1
  7. package/cpp/rnskia/dom/nodes/JsiAtlasNode.h +5 -1
  8. package/cpp/rnskia/dom/nodes/JsiImageNode.h +8 -4
  9. package/cpp/rnskia/dom/nodes/JsiShaderNodes.h +9 -38
  10. package/cpp/rnskia/dom/props/SamplingProp.h +54 -0
  11. package/ios/RNSkia-iOS/SkiaManager.mm +2 -4
  12. package/lib/commonjs/dom/types/Drawings.d.ts +3 -1
  13. package/lib/commonjs/dom/types/Drawings.js.map +1 -1
  14. package/lib/commonjs/dom/types/Shaders.d.ts +2 -3
  15. package/lib/commonjs/dom/types/Shaders.js.map +1 -1
  16. package/lib/commonjs/renderer/components/image/ImageShader.d.ts +1 -1
  17. package/lib/commonjs/renderer/components/image/ImageShader.js +0 -4
  18. package/lib/commonjs/renderer/components/image/ImageShader.js.map +1 -1
  19. package/lib/commonjs/skia/types/Canvas.d.ts +2 -2
  20. package/lib/commonjs/skia/types/Canvas.js.map +1 -1
  21. package/lib/commonjs/skia/types/Image/Image.d.ts +18 -0
  22. package/lib/commonjs/skia/types/Image/Image.js +24 -1
  23. package/lib/commonjs/skia/types/Image/Image.js.map +1 -1
  24. package/lib/commonjs/skia/types/Picture/PictureRecorder.d.ts +2 -1
  25. package/lib/commonjs/skia/types/Picture/PictureRecorder.js.map +1 -1
  26. package/lib/commonjs/skia/web/JsiSkCanvas.d.ts +2 -2
  27. package/lib/commonjs/skia/web/JsiSkCanvas.js +15 -2
  28. package/lib/commonjs/skia/web/JsiSkCanvas.js.map +1 -1
  29. package/lib/commonjs/sksg/Container.d.ts +17 -14
  30. package/lib/commonjs/sksg/Container.js +59 -62
  31. package/lib/commonjs/sksg/Container.js.map +1 -1
  32. package/lib/commonjs/sksg/HostConfig.js +4 -9
  33. package/lib/commonjs/sksg/HostConfig.js.map +1 -1
  34. package/lib/commonjs/sksg/Reconciler.js +1 -2
  35. package/lib/commonjs/sksg/Reconciler.js.map +1 -1
  36. package/lib/commonjs/sksg/Recorder/Core.d.ts +42 -37
  37. package/lib/commonjs/sksg/Recorder/Core.js +45 -38
  38. package/lib/commonjs/sksg/Recorder/Core.js.map +1 -1
  39. package/lib/commonjs/sksg/Recorder/Player.js +4 -0
  40. package/lib/commonjs/sksg/Recorder/Player.js.map +1 -1
  41. package/lib/commonjs/sksg/Recorder/Recorder.d.ts +15 -0
  42. package/lib/commonjs/sksg/Recorder/Recorder.js +23 -1
  43. package/lib/commonjs/sksg/Recorder/Recorder.js.map +1 -1
  44. package/lib/commonjs/sksg/Recorder/Visitor.js +6 -0
  45. package/lib/commonjs/sksg/Recorder/Visitor.js.map +1 -1
  46. package/lib/commonjs/sksg/Recorder/commands/Drawing.js +11 -4
  47. package/lib/commonjs/sksg/Recorder/commands/Drawing.js.map +1 -1
  48. package/lib/commonjs/sksg/Recorder/commands/Shaders.js +8 -3
  49. package/lib/commonjs/sksg/Recorder/commands/Shaders.js.map +1 -1
  50. package/lib/module/dom/types/Drawings.d.ts +3 -1
  51. package/lib/module/dom/types/Drawings.js.map +1 -1
  52. package/lib/module/dom/types/Shaders.d.ts +2 -3
  53. package/lib/module/dom/types/Shaders.js.map +1 -1
  54. package/lib/module/renderer/components/image/ImageShader.d.ts +1 -1
  55. package/lib/module/renderer/components/image/ImageShader.js +0 -4
  56. package/lib/module/renderer/components/image/ImageShader.js.map +1 -1
  57. package/lib/module/skia/types/Canvas.d.ts +2 -2
  58. package/lib/module/skia/types/Canvas.js.map +1 -1
  59. package/lib/module/skia/types/Image/Image.d.ts +18 -0
  60. package/lib/module/skia/types/Image/Image.js +21 -0
  61. package/lib/module/skia/types/Image/Image.js.map +1 -1
  62. package/lib/module/skia/types/Picture/PictureRecorder.d.ts +2 -1
  63. package/lib/module/skia/types/Picture/PictureRecorder.js.map +1 -1
  64. package/lib/module/skia/web/JsiSkCanvas.d.ts +2 -2
  65. package/lib/module/skia/web/JsiSkCanvas.js +15 -2
  66. package/lib/module/skia/web/JsiSkCanvas.js.map +1 -1
  67. package/lib/module/sksg/Container.d.ts +17 -14
  68. package/lib/module/sksg/Container.js +56 -60
  69. package/lib/module/sksg/Container.js.map +1 -1
  70. package/lib/module/sksg/HostConfig.js +4 -9
  71. package/lib/module/sksg/HostConfig.js.map +1 -1
  72. package/lib/module/sksg/Reconciler.js +2 -3
  73. package/lib/module/sksg/Reconciler.js.map +1 -1
  74. package/lib/module/sksg/Recorder/Core.d.ts +42 -37
  75. package/lib/module/sksg/Recorder/Core.js +43 -37
  76. package/lib/module/sksg/Recorder/Core.js.map +1 -1
  77. package/lib/module/sksg/Recorder/Player.js +5 -1
  78. package/lib/module/sksg/Recorder/Player.js.map +1 -1
  79. package/lib/module/sksg/Recorder/Recorder.d.ts +15 -0
  80. package/lib/module/sksg/Recorder/Recorder.js +23 -1
  81. package/lib/module/sksg/Recorder/Recorder.js.map +1 -1
  82. package/lib/module/sksg/Recorder/Visitor.js +6 -0
  83. package/lib/module/sksg/Recorder/Visitor.js.map +1 -1
  84. package/lib/module/sksg/Recorder/commands/Drawing.js +12 -5
  85. package/lib/module/sksg/Recorder/commands/Drawing.js.map +1 -1
  86. package/lib/module/sksg/Recorder/commands/Shaders.js +9 -4
  87. package/lib/module/sksg/Recorder/commands/Shaders.js.map +1 -1
  88. package/lib/typescript/lib/commonjs/renderer/components/image/ImageShader.d.ts +1 -3
  89. package/lib/typescript/lib/commonjs/skia/types/Image/Image.d.ts +21 -0
  90. package/lib/typescript/lib/commonjs/skia/web/JsiSkCanvas.d.ts +1 -1
  91. package/lib/typescript/lib/commonjs/sksg/Container.d.ts +15 -10
  92. package/lib/typescript/lib/commonjs/sksg/HostConfig.d.ts +4 -4
  93. package/lib/typescript/lib/commonjs/sksg/Reconciler.d.ts +21 -2
  94. package/lib/typescript/lib/commonjs/sksg/Recorder/Core.d.ts +1 -0
  95. package/lib/typescript/lib/commonjs/sksg/Recorder/Recorder.d.ts +7 -0
  96. package/lib/typescript/lib/module/mock/index.d.ts +18 -3
  97. package/lib/typescript/lib/module/renderer/components/image/ImageShader.d.ts +1 -3
  98. package/lib/typescript/lib/module/skia/types/Image/Image.d.ts +21 -0
  99. package/lib/typescript/lib/module/skia/web/JsiSkCanvas.d.ts +1 -1
  100. package/lib/typescript/lib/module/sksg/Container.d.ts +15 -10
  101. package/lib/typescript/lib/module/sksg/HostConfig.d.ts +4 -4
  102. package/lib/typescript/lib/module/sksg/Reconciler.d.ts +21 -2
  103. package/lib/typescript/lib/module/sksg/Recorder/Core.d.ts +1 -0
  104. package/lib/typescript/lib/module/sksg/Recorder/Recorder.d.ts +7 -0
  105. package/lib/typescript/src/dom/types/Drawings.d.ts +3 -1
  106. package/lib/typescript/src/dom/types/Shaders.d.ts +2 -3
  107. package/lib/typescript/src/renderer/components/image/ImageShader.d.ts +1 -1
  108. package/lib/typescript/src/skia/types/Canvas.d.ts +2 -2
  109. package/lib/typescript/src/skia/types/Image/Image.d.ts +18 -0
  110. package/lib/typescript/src/skia/types/Picture/PictureRecorder.d.ts +2 -1
  111. package/lib/typescript/src/skia/web/JsiSkCanvas.d.ts +2 -2
  112. package/lib/typescript/src/sksg/Container.d.ts +17 -14
  113. package/lib/typescript/src/sksg/Recorder/Core.d.ts +42 -37
  114. package/lib/typescript/src/sksg/Recorder/Recorder.d.ts +15 -0
  115. package/libs/apple/libskia.xcframework/Info.plist +35 -2
  116. package/libs/apple/libskia.xcframework/ios-arm64_arm64e/libskia.a +0 -0
  117. package/libs/apple/libskia.xcframework/ios-arm64_arm64e_x86_64-simulator/libskia.a +0 -0
  118. package/libs/apple/libskia.xcframework/macos-arm64_x86_64/libskia.a +0 -0
  119. package/libs/apple/libskia.xcframework/tvos-arm64_arm64e/libskia.a +0 -0
  120. package/libs/apple/libskia.xcframework/tvos-arm64_arm64e_x86_64-simulator/libskia.a +0 -0
  121. package/libs/apple/libskottie.xcframework/Info.plist +36 -3
  122. package/libs/apple/libskottie.xcframework/ios-arm64_arm64e/libskottie.a +0 -0
  123. package/libs/apple/libskottie.xcframework/ios-arm64_arm64e_x86_64-simulator/libskottie.a +0 -0
  124. package/libs/apple/libskottie.xcframework/macos-arm64_x86_64/libskottie.a +0 -0
  125. package/libs/apple/libskottie.xcframework/tvos-arm64_arm64e/libskottie.a +0 -0
  126. package/libs/apple/libskottie.xcframework/tvos-arm64_arm64e_x86_64-simulator/libskottie.a +0 -0
  127. package/libs/apple/libskparagraph.xcframework/Info.plist +40 -7
  128. package/libs/apple/libskparagraph.xcframework/ios-arm64_arm64e/libskparagraph.a +0 -0
  129. package/libs/apple/libskparagraph.xcframework/ios-arm64_arm64e_x86_64-simulator/libskparagraph.a +0 -0
  130. package/libs/apple/libskparagraph.xcframework/macos-arm64_x86_64/libskparagraph.a +0 -0
  131. package/libs/apple/libskparagraph.xcframework/tvos-arm64_arm64e/libskparagraph.a +0 -0
  132. package/libs/apple/libskparagraph.xcframework/tvos-arm64_arm64e_x86_64-simulator/libskparagraph.a +0 -0
  133. package/libs/apple/libsksg.xcframework/Info.plist +35 -2
  134. package/libs/apple/libsksg.xcframework/ios-arm64_arm64e/libsksg.a +0 -0
  135. package/libs/apple/libsksg.xcframework/ios-arm64_arm64e_x86_64-simulator/libsksg.a +0 -0
  136. package/libs/apple/libsksg.xcframework/macos-arm64_x86_64/libsksg.a +0 -0
  137. package/libs/apple/libsksg.xcframework/tvos-arm64_arm64e/libsksg.a +0 -0
  138. package/libs/apple/libsksg.xcframework/tvos-arm64_arm64e_x86_64-simulator/libsksg.a +0 -0
  139. package/libs/apple/libskshaper.xcframework/Info.plist +33 -0
  140. package/libs/apple/libskshaper.xcframework/ios-arm64_arm64e/libskshaper.a +0 -0
  141. package/libs/apple/libskshaper.xcframework/ios-arm64_arm64e_x86_64-simulator/libskshaper.a +0 -0
  142. package/libs/apple/libskshaper.xcframework/macos-arm64_x86_64/libskshaper.a +0 -0
  143. package/libs/apple/libskshaper.xcframework/tvos-arm64_arm64e/libskshaper.a +0 -0
  144. package/libs/apple/libskshaper.xcframework/tvos-arm64_arm64e_x86_64-simulator/libskshaper.a +0 -0
  145. package/libs/apple/libskunicode_core.xcframework/Info.plist +36 -3
  146. package/libs/apple/libskunicode_core.xcframework/ios-arm64_arm64e/libskunicode_core.a +0 -0
  147. package/libs/apple/libskunicode_core.xcframework/ios-arm64_arm64e_x86_64-simulator/libskunicode_core.a +0 -0
  148. package/libs/apple/libskunicode_core.xcframework/macos-arm64_x86_64/libskunicode_core.a +0 -0
  149. package/libs/apple/libskunicode_core.xcframework/tvos-arm64_arm64e/libskunicode_core.a +0 -0
  150. package/libs/apple/libskunicode_core.xcframework/tvos-arm64_arm64e_x86_64-simulator/libskunicode_core.a +0 -0
  151. package/libs/apple/libskunicode_libgrapheme.xcframework/Info.plist +35 -2
  152. package/libs/apple/libskunicode_libgrapheme.xcframework/ios-arm64_arm64e/libskunicode_libgrapheme.a +0 -0
  153. package/libs/apple/libskunicode_libgrapheme.xcframework/ios-arm64_arm64e_x86_64-simulator/libskunicode_libgrapheme.a +0 -0
  154. package/libs/apple/libskunicode_libgrapheme.xcframework/macos-arm64_x86_64/libskunicode_libgrapheme.a +0 -0
  155. package/libs/apple/libskunicode_libgrapheme.xcframework/tvos-arm64_arm64e/libskunicode_libgrapheme.a +0 -0
  156. package/libs/apple/libskunicode_libgrapheme.xcframework/tvos-arm64_arm64e_x86_64-simulator/libskunicode_libgrapheme.a +0 -0
  157. package/libs/apple/libsvg.xcframework/Info.plist +36 -3
  158. package/libs/apple/libsvg.xcframework/ios-arm64_arm64e/libsvg.a +0 -0
  159. package/libs/apple/libsvg.xcframework/ios-arm64_arm64e_x86_64-simulator/libsvg.a +0 -0
  160. package/libs/apple/libsvg.xcframework/macos-arm64_x86_64/libsvg.a +0 -0
  161. package/libs/apple/libsvg.xcframework/tvos-arm64_arm64e/libsvg.a +0 -0
  162. package/libs/apple/libsvg.xcframework/tvos-arm64_arm64e_x86_64-simulator/libsvg.a +0 -0
  163. package/package.json +3 -2
  164. package/react-native-skia.podspec +2 -2
  165. package/src/__tests__/snapshots/animated-images/bird.png +0 -0
  166. package/src/__tests__/snapshots/demos/product.png +0 -0
  167. package/src/__tests__/snapshots/demos/product2.png +0 -0
  168. package/src/__tests__/snapshots/images/bundle-android.png +0 -0
  169. package/src/__tests__/snapshots/images/bundle-ios.png +0 -0
  170. package/src/__tests__/snapshots/images/bundle-node.png +0 -0
  171. package/src/__tests__/snapshots/images/filter.png +0 -0
  172. package/src/dom/types/Drawings.ts +3 -0
  173. package/src/dom/types/Shaders.ts +2 -4
  174. package/src/renderer/__tests__/e2e/Text.spec.tsx +1 -1
  175. package/src/renderer/components/image/ImageShader.tsx +2 -15
  176. package/src/skia/types/Canvas.ts +2 -3
  177. package/src/skia/types/Image/Image.ts +14 -0
  178. package/src/skia/types/Picture/PictureRecorder.ts +2 -1
  179. package/src/skia/web/JsiSkCanvas.ts +50 -29
  180. package/src/sksg/Container.ts +64 -68
  181. package/src/sksg/HostConfig.ts +4 -9
  182. package/src/sksg/Reconciler.ts +3 -3
  183. package/src/sksg/Recorder/Core.ts +10 -0
  184. package/src/sksg/Recorder/Player.ts +5 -1
  185. package/src/sksg/Recorder/Recorder.ts +36 -1
  186. package/src/sksg/Recorder/Visitor.ts +6 -0
  187. package/src/sksg/Recorder/commands/Drawing.ts +33 -4
  188. package/src/sksg/Recorder/commands/Shaders.ts +21 -8
  189. package/lib/commonjs/sksg/Recorder/Recording.d.ts +0 -7
  190. package/lib/commonjs/sksg/Recorder/Recording.js +0 -12
  191. package/lib/commonjs/sksg/Recorder/Recording.js.map +0 -1
  192. package/lib/module/sksg/Recorder/Recording.d.ts +0 -7
  193. package/lib/module/sksg/Recorder/Recording.js +0 -5
  194. package/lib/module/sksg/Recorder/Recording.js.map +0 -1
  195. package/lib/typescript/lib/commonjs/sksg/Recorder/Recording.d.ts +0 -5
  196. package/lib/typescript/lib/module/sksg/Recorder/Recording.d.ts +0 -4
  197. package/lib/typescript/src/sksg/Recorder/Recording.d.ts +0 -7
  198. package/src/sksg/Recorder/Recording.ts +0 -13
@@ -1,7 +1,6 @@
1
1
  import type {
2
2
  Color,
3
- FilterMode,
4
- MipmapMode,
3
+ SamplingOptions,
5
4
  SkImage,
6
5
  SkRect,
7
6
  SkRuntimeEffect,
@@ -26,11 +25,10 @@ export interface ShaderProps extends TransformProps, ChildrenProps {
26
25
  export interface ImageShaderProps extends TransformProps, Partial<RectCtor> {
27
26
  tx: SkEnum<typeof TileMode>;
28
27
  ty: SkEnum<typeof TileMode>;
29
- fm: SkEnum<typeof FilterMode>;
30
- mm: SkEnum<typeof MipmapMode>;
31
28
  fit: Fit;
32
29
  rect?: SkRect;
33
30
  image: SkImage | null;
31
+ sampling?: SamplingOptions;
34
32
  }
35
33
 
36
34
  export interface ColorProps {
@@ -18,7 +18,7 @@ describe("Text", () => {
18
18
  },
19
19
  { font }
20
20
  );
21
- expect(result).toEqual([892, 896]);
21
+ expect(result).toEqual(surface.OS === "ios" ? [0, 0] : [892, 896]);
22
22
  });
23
23
  it("Should calculate chinese text width correctly", async () => {
24
24
  const font = fonts.NotoSansSCRegular;
@@ -6,24 +6,11 @@ import type { SkiaDefaultProps } from "../../processors";
6
6
  export const ImageShader = ({
7
7
  tx = "decal",
8
8
  ty = "decal",
9
- fm = "nearest",
10
- mm = "none",
11
9
  fit = "none",
12
10
  transform = [],
13
11
  ...props
14
- }: SkiaDefaultProps<
15
- ImageShaderProps,
16
- "tx" | "ty" | "fm" | "mm" | "fit" | "transform"
17
- >) => {
12
+ }: SkiaDefaultProps<ImageShaderProps, "tx" | "ty" | "fit" | "transform">) => {
18
13
  return (
19
- <skImageShader
20
- tx={tx}
21
- ty={ty}
22
- fm={fm}
23
- mm={mm}
24
- fit={fit}
25
- transform={transform}
26
- {...props}
27
- />
14
+ <skImageShader tx={tx} ty={ty} fit={fit} transform={transform} {...props} />
28
15
  );
29
16
  };
@@ -7,8 +7,7 @@ import type {
7
7
  MipmapMode,
8
8
  FilterMode,
9
9
  ImageInfo,
10
- CubicResampler,
11
- FilterOptions,
10
+ SamplingOptions,
12
11
  } from "./Image";
13
12
  import type { SkSVG } from "./SVG";
14
13
  import type { SkColor } from "./Color";
@@ -521,7 +520,7 @@ export interface SkCanvas {
521
520
  paint: SkPaint,
522
521
  blendMode?: BlendMode,
523
522
  colors?: SkColor[],
524
- sampling?: CubicResampler | FilterOptions
523
+ sampling?: SamplingOptions
525
524
  ): void;
526
525
 
527
526
  /** Read Image pixels
@@ -32,6 +32,20 @@ export enum ImageFormat {
32
32
  WEBP = 6,
33
33
  }
34
34
 
35
+ export type SamplingOptions = CubicResampler | FilterOptions;
36
+
37
+ export const isCubicSampling = (
38
+ sampling: SamplingOptions
39
+ ): sampling is CubicResampler => {
40
+ "worklet";
41
+ return "B" in sampling && "C" in sampling;
42
+ };
43
+
44
+ export const MitchellCubicSampling = { B: 1 / 3.0, C: 1 / 3.0 };
45
+ export const CatmullRomCubicSampling = { B: 0, C: 1 / 2.0 };
46
+ export const CubicSampling = { B: 0, C: 0 };
47
+ export const MakeCubic = (B: number, C: number) => ({ B, C });
48
+
35
49
  export interface SkImage extends SkJSIInstance<"Image"> {
36
50
  /**
37
51
  * Returns the possibly scaled height of the image.
@@ -1,9 +1,10 @@
1
1
  import type { SkCanvas } from "../Canvas";
2
+ import type { SkJSIInstance } from "../JsiInstance";
2
3
  import type { SkRect } from "../Rect";
3
4
 
4
5
  import type { SkPicture } from "./Picture";
5
6
 
6
- export interface SkPictureRecorder {
7
+ export interface SkPictureRecorder extends SkJSIInstance<"PictureRecorder"> {
7
8
  /**
8
9
  * Returns a canvas on which to draw. When done drawing, call finishRecordingAsPicture()
9
10
  *
@@ -1,31 +1,37 @@
1
- import type { Canvas, CanvasKit } from "canvaskit-wasm";
2
-
3
1
  import type {
4
- BlendMode,
5
- ClipOp,
6
- FilterMode,
7
- MipmapMode,
8
- PointMode,
9
- SaveLayerFlag,
10
- ImageInfo,
11
- SkCanvas,
12
- SkColor,
13
- SkFont,
14
- SkImage,
15
- SkImageFilter,
16
- SkMatrix,
17
- SkPaint,
18
- SkPath,
19
- SkPicture,
20
- SkPoint,
21
- SkRect,
22
- InputRRect,
23
- SkSVG,
24
- SkTextBlob,
25
- SkVertices,
26
- SkRSXform,
27
- CubicResampler,
28
- FilterOptions,
2
+ Canvas,
3
+ CanvasKit,
4
+ CubicResampler as CKCubicResampler,
5
+ FilterOptions as CKFilterOptions,
6
+ } from "canvaskit-wasm";
7
+
8
+ import {
9
+ type BlendMode,
10
+ type ClipOp,
11
+ type FilterMode,
12
+ type MipmapMode,
13
+ type PointMode,
14
+ type SaveLayerFlag,
15
+ type ImageInfo,
16
+ type SkCanvas,
17
+ type SkColor,
18
+ type SkFont,
19
+ type SkImage,
20
+ type SkImageFilter,
21
+ type SkMatrix,
22
+ type SkPaint,
23
+ type SkPath,
24
+ type SkPicture,
25
+ type SkPoint,
26
+ type SkRect,
27
+ type InputRRect,
28
+ type SkSVG,
29
+ type SkTextBlob,
30
+ type SkVertices,
31
+ type SkRSXform,
32
+ type CubicResampler,
33
+ type FilterOptions,
34
+ isCubicSampling,
29
35
  } from "../types";
30
36
 
31
37
  import { getEnum, HostObject } from "./Host";
@@ -398,7 +404,7 @@ export class JsiSkCanvas
398
404
  paint: SkPaint,
399
405
  blendMode?: BlendMode,
400
406
  colors?: SkColor[],
401
- _sampling?: CubicResampler | FilterOptions
407
+ sampling?: CubicResampler | FilterOptions
402
408
  ) {
403
409
  const src = srcs.flatMap((s) =>
404
410
  Array.from(JsiSkRect.fromValue(this.CanvasKit, s))
@@ -412,6 +418,20 @@ export class JsiSkCanvas
412
418
  cls[i] = this.CanvasKit.ColorAsInt(r * 255, g * 255, b * 255, a * 255);
413
419
  }
414
420
  }
421
+ let ckSampling: CKCubicResampler | CKFilterOptions = {
422
+ filter: this.CanvasKit.FilterMode.Linear,
423
+ mipmap: this.CanvasKit.MipmapMode.None,
424
+ };
425
+ if (sampling && isCubicSampling(sampling)) {
426
+ ckSampling = sampling;
427
+ } else if (sampling) {
428
+ ckSampling = {
429
+ filter: getEnum(this.CanvasKit.FilterMode, sampling.filter),
430
+ mipmap: sampling.mipmap
431
+ ? getEnum(this.CanvasKit.MipmapMode, sampling.mipmap)
432
+ : this.CanvasKit.MipmapMode.None,
433
+ };
434
+ }
415
435
  this.ref.drawAtlas(
416
436
  JsiSkImage.fromValue(atlas),
417
437
  src,
@@ -420,7 +440,8 @@ export class JsiSkCanvas
420
440
  blendMode
421
441
  ? getEnum(this.CanvasKit.BlendMode, blendMode)
422
442
  : this.CanvasKit.BlendMode.DstOver,
423
- cls
443
+ cls,
444
+ ckSampling
424
445
  );
425
446
  }
426
447
 
@@ -1,108 +1,104 @@
1
- import { type SharedValue } from "react-native-reanimated";
2
-
3
1
  import Rea from "../external/reanimated/ReanimatedProxy";
4
2
  import type { Skia, SkCanvas } from "../skia/types";
3
+ import { HAS_REANIMATED_3 } from "../external/reanimated/renderHelpers";
5
4
 
6
5
  import type { Node } from "./Node";
7
- import { isSharedValue } from "./utils";
6
+ import type { Recording } from "./Recorder/Recorder";
8
7
  import { Recorder } from "./Recorder/Recorder";
9
8
  import { visit } from "./Recorder/Visitor";
10
9
  import { replay } from "./Recorder/Player";
11
10
  import { createDrawingContext } from "./Recorder/DrawingContext";
12
- import { createRecording, type Recording } from "./Recorder/Recording";
13
11
 
14
12
  const drawOnscreen = (Skia: Skia, nativeId: number, recording: Recording) => {
15
13
  "worklet";
14
+
16
15
  const rec = Skia.PictureRecorder();
17
16
  const canvas = rec.beginRecording();
18
17
  // const start = performance.now();
19
18
 
20
- // TODO: because the pool is not a shared value here, it is copied on every frame
21
19
  const ctx = createDrawingContext(Skia, recording.paintPool, canvas);
22
- //console.log(recording.commands);
23
20
  replay(ctx, recording.commands);
24
21
  const picture = rec.finishRecordingAsPicture();
25
22
  //const end = performance.now();
26
23
  //console.log("Recording time: ", end - start);
27
24
  SkiaViewApi.setJsiProperty(nativeId, "picture", picture);
25
+ rec.dispose();
26
+ picture.dispose();
28
27
  };
29
28
 
30
- export class Container {
31
- private _root: Node[] = [];
32
- private _recording: Recording | null = null;
33
- public unmounted = false;
29
+ export abstract class Container {
30
+ public root: Node[] = [];
31
+ protected recording: Recording | null = null;
34
32
 
35
- private values = new Set<SharedValue<unknown>>();
36
- private mapperId: number | null = null;
33
+ constructor(protected Skia: Skia, protected nativeId: number) {}
37
34
 
38
- constructor(public Skia: Skia, private nativeId: number) {}
39
-
40
- get root() {
41
- return this._root;
42
- }
43
-
44
- set root(root: Node[]) {
45
- const isOnscreen = this.nativeId !== -1;
46
- if (isOnscreen) {
47
- if (this.mapperId !== null) {
48
- Rea.stopMapper(this.mapperId);
49
- }
50
- const { nativeId, Skia, _recording } = this;
51
- this.mapperId = Rea.startMapper(() => {
52
- "worklet";
53
- drawOnscreen(Skia, nativeId, _recording!);
54
- }, Array.from(this.values));
35
+ drawOnCanvas(canvas: SkCanvas) {
36
+ if (!this.recording) {
37
+ throw new Error("No recording to draw");
55
38
  }
56
- this._root = root;
57
- const recorder = new Recorder();
58
- visit(recorder, root);
59
- this._recording = createRecording(recorder.commands);
39
+ const ctx = createDrawingContext(
40
+ this.Skia,
41
+ this.recording.paintPool,
42
+ canvas
43
+ );
44
+ //console.log(this.recording.commands);
45
+ replay(ctx, this.recording.commands);
60
46
  }
61
47
 
62
- clear() {
63
- console.log("clear container");
48
+ abstract redraw(): void;
49
+ }
50
+
51
+ class StaticContainer extends Container {
52
+ constructor(Skia: Skia, nativeId: number) {
53
+ super(Skia, nativeId);
64
54
  }
65
55
 
66
56
  redraw() {
67
- const isOnscreen = this.nativeId !== -1;
68
- if (isOnscreen) {
69
- const { nativeId, Skia, _recording } = this;
70
- Rea.runOnUI(() => {
71
- drawOnscreen(Skia, nativeId, _recording!);
72
- })();
57
+ const recorder = new Recorder();
58
+ visit(recorder, this.root);
59
+ this.recording = recorder.getRecording();
60
+ const isOnScreen = this.nativeId !== -1;
61
+ if (isOnScreen) {
62
+ const rec = this.Skia.PictureRecorder();
63
+ const canvas = rec.beginRecording();
64
+ this.drawOnCanvas(canvas);
65
+ const picture = rec.finishRecordingAsPicture();
66
+ SkiaViewApi.setJsiProperty(this.nativeId, "picture", picture);
73
67
  }
74
68
  }
69
+ }
75
70
 
76
- getNativeId() {
77
- return this.nativeId;
78
- }
79
-
80
- unregisterValues(values: object) {
81
- Object.values(values)
82
- .filter(isSharedValue)
83
- .forEach((value) => {
84
- this.values.delete(value);
85
- });
86
- }
71
+ class ReanimatedContainer extends Container {
72
+ private mapperId: number | null = null;
87
73
 
88
- registerValues(values: object) {
89
- Object.values(values)
90
- .filter(isSharedValue)
91
- .forEach((value) => {
92
- this.values.add(value);
93
- });
74
+ constructor(Skia: Skia, nativeId: number) {
75
+ super(Skia, nativeId);
94
76
  }
95
77
 
96
- drawOnCanvas(canvas: SkCanvas) {
97
- if (!this._recording) {
98
- throw new Error("No recording to draw");
78
+ redraw() {
79
+ if (this.mapperId !== null) {
80
+ Rea.stopMapper(this.mapperId);
81
+ }
82
+ const recorder = new Recorder();
83
+ visit(recorder, this.root);
84
+ const record = recorder.getRecording();
85
+ const { animationValues } = record;
86
+ this.recording = {
87
+ commands: record.commands,
88
+ paintPool: record.paintPool,
89
+ };
90
+ if (animationValues.size > 0) {
91
+ const { nativeId, Skia, recording } = this;
92
+ this.mapperId = Rea.startMapper(() => {
93
+ "worklet";
94
+ drawOnscreen(Skia, nativeId, recording!);
95
+ }, Array.from(animationValues));
99
96
  }
100
- const ctx = createDrawingContext(
101
- this.Skia,
102
- this._recording.paintPool,
103
- canvas
104
- );
105
- //console.log(this._recording);
106
- replay(ctx, this._recording.commands);
107
97
  }
108
98
  }
99
+
100
+ export const createContainer = (Skia: Skia, nativeId: number) => {
101
+ return HAS_REANIMATED_3 && nativeId !== -1
102
+ ? new ReanimatedContainer(Skia, nativeId)
103
+ : new StaticContainer(Skia, nativeId);
104
+ };
@@ -85,14 +85,13 @@ export const sksgHostConfig: SkiaHostConfig = {
85
85
  createInstance(
86
86
  type,
87
87
  propsWithChildren,
88
- container,
88
+ _container,
89
89
  _hostContext,
90
90
  _internalInstanceHandle
91
91
  ) {
92
92
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
93
93
  const { children, ...props } = propsWithChildren as any;
94
94
  debug("createInstance", type);
95
- container.registerValues(props);
96
95
  const instance = {
97
96
  type,
98
97
  props,
@@ -121,7 +120,7 @@ export const sksgHostConfig: SkiaHostConfig = {
121
120
  debug("commitMount");
122
121
  },
123
122
 
124
- prepareForCommit(_containerInfo) {
123
+ prepareForCommit(_container: Container) {
125
124
  debug("prepareForCommit");
126
125
  return null;
127
126
  },
@@ -144,9 +143,8 @@ export const sksgHostConfig: SkiaHostConfig = {
144
143
  // textInstance.instance = newText;
145
144
  },
146
145
 
147
- clearContainer: (container) => {
146
+ clearContainer: (_container) => {
148
147
  debug("clearContainer");
149
- container.clear();
150
148
  },
151
149
 
152
150
  prepareUpdate(
@@ -162,8 +160,6 @@ export const sksgHostConfig: SkiaHostConfig = {
162
160
  if (propsAreEqual) {
163
161
  return null;
164
162
  }
165
- container.unregisterValues(oldProps);
166
- container.registerValues(newProps);
167
163
  return container;
168
164
  },
169
165
 
@@ -208,7 +204,6 @@ export const sksgHostConfig: SkiaHostConfig = {
208
204
  },
209
205
 
210
206
  replaceContainerChildren(container: Container, newChildren: ChildSet) {
211
- debug("replaceContainerChildren");
212
207
  container.root = newChildren;
213
208
  },
214
209
 
@@ -229,7 +224,7 @@ export const sksgHostConfig: SkiaHostConfig = {
229
224
  getCurrentEventPriority: () => DefaultEventPriority,
230
225
  beforeActiveInstanceBlur: () => {},
231
226
  afterActiveInstanceBlur: () => {},
232
- detachDeletedInstance: () => {},
227
+ detachDeletedInstance: (_node: Instance) => {},
233
228
  getInstanceFromNode: function (_node): Fiber | null | undefined {
234
229
  throw new Error("Function not implemented.");
235
230
  },
@@ -6,7 +6,8 @@ import type { SkCanvas, Skia } from "../skia/types";
6
6
  import { NodeType } from "../dom/types";
7
7
 
8
8
  import { debug, sksgHostConfig } from "./HostConfig";
9
- import { Container } from "./Container";
9
+ import type { Container } from "./Container";
10
+ import { createContainer } from "./Container";
10
11
 
11
12
  const skiaReconciler = ReactReconciler(sksgHostConfig);
12
13
 
@@ -21,7 +22,7 @@ export class SkiaSGRoot {
21
22
  private container: Container;
22
23
 
23
24
  constructor(public Skia: Skia, nativeId = -1) {
24
- this.container = new Container(Skia, nativeId);
25
+ this.container = createContainer(Skia, nativeId);
25
26
  this.root = skiaReconciler.createContainer(
26
27
  this.container,
27
28
  0,
@@ -58,7 +59,6 @@ export class SkiaSGRoot {
58
59
  }
59
60
 
60
61
  unmount() {
61
- this.container.unmounted = true;
62
62
  skiaReconciler.updateContainer(null, this.root, null, () => {
63
63
  debug("unmountContainer");
64
64
  });
@@ -68,6 +68,7 @@ import type {
68
68
  // }
69
69
  export enum CommandType {
70
70
  // Context
71
+ Group,
71
72
  SavePaint,
72
73
  RestorePaint,
73
74
  SaveCTM,
@@ -133,6 +134,15 @@ export const isCommand = <T extends CommandType>(
133
134
  return command.type === type;
134
135
  };
135
136
 
137
+ interface GroupCommand extends Command<CommandType.Group> {
138
+ children: Command[];
139
+ }
140
+
141
+ export const isGroup = (command: Command): command is GroupCommand => {
142
+ "worklet";
143
+ return command.type === CommandType.Group;
144
+ };
145
+
136
146
  interface Props {
137
147
  [CommandType.DrawImage]: ImageProps;
138
148
  [CommandType.DrawCircle]: CircleProps;
@@ -43,6 +43,7 @@ import {
43
43
  CommandType,
44
44
  isCommand,
45
45
  isDrawCommand,
46
+ isGroup,
46
47
  materializeProps,
47
48
  type Command,
48
49
  } from "./Core";
@@ -50,7 +51,10 @@ import type { DrawingContext } from "./DrawingContext";
50
51
 
51
52
  const play = (ctx: DrawingContext, command: Command) => {
52
53
  "worklet";
53
-
54
+ if (isGroup(command)) {
55
+ command.children.forEach((child) => play(ctx, child));
56
+ return;
57
+ }
54
58
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
55
59
  materializeProps(command as any);
56
60
  if (isCommand(command, CommandType.SaveBackdropFilter)) {
@@ -30,12 +30,36 @@ import type {
30
30
  import type { AnimatedProps } from "../../renderer";
31
31
  import { isSharedValue } from "../utils";
32
32
  import { isColorFilter, isImageFilter, isPathEffect, isShader } from "../Node";
33
+ import type { SkPaint } from "../../skia/types";
33
34
 
34
35
  import { CommandType } from "./Core";
35
36
  import type { Command } from "./Core";
36
37
 
38
+ export interface Recording {
39
+ commands: Command[];
40
+ paintPool: SkPaint[];
41
+ }
42
+
43
+ interface AnimationValues {
44
+ animationValues: Set<SharedValue<unknown>>;
45
+ }
46
+
37
47
  export class Recorder {
38
48
  commands: Command[] = [];
49
+ cursors: Command[][] = [];
50
+ animationValues: Set<SharedValue<unknown>> = new Set();
51
+
52
+ constructor() {
53
+ this.cursors.push(this.commands);
54
+ }
55
+
56
+ getRecording(): Recording & AnimationValues {
57
+ return {
58
+ commands: this.commands,
59
+ paintPool: [],
60
+ animationValues: this.animationValues,
61
+ };
62
+ }
39
63
 
40
64
  private processProps(props: Record<string, unknown>) {
41
65
  const animatedProps: Record<string, SharedValue<unknown>> = {};
@@ -44,6 +68,7 @@ export class Recorder {
44
68
  for (const key in props) {
45
69
  const prop = props[key];
46
70
  if (isSharedValue(prop)) {
71
+ this.animationValues.add(prop);
47
72
  props[key] = prop.value;
48
73
  animatedProps[key] = prop;
49
74
  hasAnimatedProps = true;
@@ -65,7 +90,17 @@ export class Recorder {
65
90
  command.animatedProps = animatedProps;
66
91
  }
67
92
  }
68
- this.commands.push(command);
93
+ this.cursors[this.cursors.length - 1].push(command);
94
+ }
95
+
96
+ saveGroup() {
97
+ const children: Command[] = [];
98
+ this.add({ type: CommandType.Group, children });
99
+ this.cursors.push(children);
100
+ }
101
+
102
+ restoreGroup() {
103
+ this.cursors.pop();
69
104
  }
70
105
 
71
106
  savePaint(props: AnimatedProps<PaintProps>) {
@@ -196,6 +196,9 @@ const pushPaints = (recorder: Recorder, paints: Node<any>[]) => {
196
196
  };
197
197
 
198
198
  const visitNode = (recorder: Recorder, node: Node<any>) => {
199
+ if (node.type === NodeType.Group) {
200
+ recorder.saveGroup();
201
+ }
199
202
  const { props } = node;
200
203
  const {
201
204
  colorFilters,
@@ -315,6 +318,9 @@ const visitNode = (recorder: Recorder, node: Node<any>) => {
315
318
  if (shouldRestore) {
316
319
  recorder.restoreCTM();
317
320
  }
321
+ if (node.type === NodeType.Group) {
322
+ recorder.restoreGroup();
323
+ }
318
324
  };
319
325
 
320
326
  export const visit = (recorder: Recorder, root: Node[]) => {
@@ -40,7 +40,10 @@ import {
40
40
  BlurStyle,
41
41
  ClipOp,
42
42
  FillType,
43
+ FilterMode,
44
+ isCubicSampling,
43
45
  isRRect,
46
+ MipmapMode,
44
47
  PointMode,
45
48
  VertexMode,
46
49
  } from "../../../skia/types";
@@ -117,7 +120,7 @@ export const drawBox = (
117
120
 
118
121
  export const drawImage = (ctx: DrawingContext, props: ImageProps) => {
119
122
  "worklet";
120
- const { image } = props;
123
+ const { image, sampling } = props;
121
124
  if (image) {
122
125
  const fit = props.fit ?? "contain";
123
126
  const rect = processRect(ctx.Skia, props);
@@ -131,7 +134,25 @@ export const drawImage = (ctx: DrawingContext, props: ImageProps) => {
131
134
  },
132
135
  rect
133
136
  );
134
- ctx.canvas.drawImageRect(image, src, dst, ctx.paint);
137
+ if (sampling && isCubicSampling(sampling)) {
138
+ ctx.canvas.drawImageRectCubic(
139
+ image,
140
+ src,
141
+ dst,
142
+ sampling.B,
143
+ sampling.C,
144
+ ctx.paint
145
+ );
146
+ } else {
147
+ ctx.canvas.drawImageRectOptions(
148
+ image,
149
+ src,
150
+ dst,
151
+ sampling?.filter ?? FilterMode.Linear,
152
+ sampling?.mipmap ?? MipmapMode.None,
153
+ ctx.paint
154
+ );
155
+ }
135
156
  }
136
157
  };
137
158
 
@@ -349,10 +370,18 @@ export const drawPicture = (ctx: DrawingContext, props: PictureProps) => {
349
370
 
350
371
  export const drawAtlas = (ctx: DrawingContext, props: AtlasProps) => {
351
372
  "worklet";
352
- const { image, sprites, transforms, colors, blendMode } = props;
373
+ const { image, sprites, transforms, colors, blendMode, sampling } = props;
353
374
  const blend = blendMode ? BlendMode[enumKey(blendMode)] : undefined;
354
375
  if (image) {
355
- ctx.canvas.drawAtlas(image, sprites, transforms, ctx.paint, blend, colors);
376
+ ctx.canvas.drawAtlas(
377
+ image,
378
+ sprites,
379
+ transforms,
380
+ ctx.paint,
381
+ blend,
382
+ colors,
383
+ sampling
384
+ );
356
385
  }
357
386
  };
358
387