@shopify/react-native-skia 1.8.2 → 1.9.0

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 (178) 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 -61
  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/Recorder.d.ts +11 -0
  37. package/lib/commonjs/sksg/Recorder/Recorder.js +9 -0
  38. package/lib/commonjs/sksg/Recorder/Recorder.js.map +1 -1
  39. package/lib/commonjs/sksg/Recorder/commands/Drawing.js +11 -4
  40. package/lib/commonjs/sksg/Recorder/commands/Drawing.js.map +1 -1
  41. package/lib/commonjs/sksg/Recorder/commands/Shaders.js +8 -3
  42. package/lib/commonjs/sksg/Recorder/commands/Shaders.js.map +1 -1
  43. package/lib/module/dom/types/Drawings.d.ts +3 -1
  44. package/lib/module/dom/types/Drawings.js.map +1 -1
  45. package/lib/module/dom/types/Shaders.d.ts +2 -3
  46. package/lib/module/dom/types/Shaders.js.map +1 -1
  47. package/lib/module/renderer/components/image/ImageShader.d.ts +1 -1
  48. package/lib/module/renderer/components/image/ImageShader.js +0 -4
  49. package/lib/module/renderer/components/image/ImageShader.js.map +1 -1
  50. package/lib/module/skia/types/Canvas.d.ts +2 -2
  51. package/lib/module/skia/types/Canvas.js.map +1 -1
  52. package/lib/module/skia/types/Image/Image.d.ts +18 -0
  53. package/lib/module/skia/types/Image/Image.js +21 -0
  54. package/lib/module/skia/types/Image/Image.js.map +1 -1
  55. package/lib/module/skia/types/Picture/PictureRecorder.d.ts +2 -1
  56. package/lib/module/skia/types/Picture/PictureRecorder.js.map +1 -1
  57. package/lib/module/skia/web/JsiSkCanvas.d.ts +2 -2
  58. package/lib/module/skia/web/JsiSkCanvas.js +15 -2
  59. package/lib/module/skia/web/JsiSkCanvas.js.map +1 -1
  60. package/lib/module/sksg/Container.d.ts +17 -14
  61. package/lib/module/sksg/Container.js +56 -59
  62. package/lib/module/sksg/Container.js.map +1 -1
  63. package/lib/module/sksg/HostConfig.js +4 -9
  64. package/lib/module/sksg/HostConfig.js.map +1 -1
  65. package/lib/module/sksg/Reconciler.js +2 -3
  66. package/lib/module/sksg/Reconciler.js.map +1 -1
  67. package/lib/module/sksg/Recorder/Recorder.d.ts +11 -0
  68. package/lib/module/sksg/Recorder/Recorder.js +9 -0
  69. package/lib/module/sksg/Recorder/Recorder.js.map +1 -1
  70. package/lib/module/sksg/Recorder/commands/Drawing.js +12 -5
  71. package/lib/module/sksg/Recorder/commands/Drawing.js.map +1 -1
  72. package/lib/module/sksg/Recorder/commands/Shaders.js +9 -4
  73. package/lib/module/sksg/Recorder/commands/Shaders.js.map +1 -1
  74. package/lib/typescript/lib/commonjs/renderer/components/image/ImageShader.d.ts +1 -3
  75. package/lib/typescript/lib/commonjs/skia/types/Image/Image.d.ts +21 -0
  76. package/lib/typescript/lib/commonjs/skia/web/JsiSkCanvas.d.ts +1 -1
  77. package/lib/typescript/lib/commonjs/sksg/Container.d.ts +15 -10
  78. package/lib/typescript/lib/commonjs/sksg/HostConfig.d.ts +4 -4
  79. package/lib/typescript/lib/commonjs/sksg/Reconciler.d.ts +21 -2
  80. package/lib/typescript/lib/commonjs/sksg/Recorder/Recorder.d.ts +5 -0
  81. package/lib/typescript/lib/module/mock/index.d.ts +18 -3
  82. package/lib/typescript/lib/module/renderer/components/image/ImageShader.d.ts +1 -3
  83. package/lib/typescript/lib/module/skia/types/Image/Image.d.ts +21 -0
  84. package/lib/typescript/lib/module/skia/web/JsiSkCanvas.d.ts +1 -1
  85. package/lib/typescript/lib/module/sksg/Container.d.ts +15 -10
  86. package/lib/typescript/lib/module/sksg/HostConfig.d.ts +4 -4
  87. package/lib/typescript/lib/module/sksg/Reconciler.d.ts +21 -2
  88. package/lib/typescript/lib/module/sksg/Recorder/Recorder.d.ts +5 -0
  89. package/lib/typescript/src/dom/types/Drawings.d.ts +3 -1
  90. package/lib/typescript/src/dom/types/Shaders.d.ts +2 -3
  91. package/lib/typescript/src/renderer/components/image/ImageShader.d.ts +1 -1
  92. package/lib/typescript/src/skia/types/Canvas.d.ts +2 -2
  93. package/lib/typescript/src/skia/types/Image/Image.d.ts +18 -0
  94. package/lib/typescript/src/skia/types/Picture/PictureRecorder.d.ts +2 -1
  95. package/lib/typescript/src/skia/web/JsiSkCanvas.d.ts +2 -2
  96. package/lib/typescript/src/sksg/Container.d.ts +17 -14
  97. package/lib/typescript/src/sksg/Recorder/Recorder.d.ts +11 -0
  98. package/libs/apple/libskia.xcframework/Info.plist +35 -2
  99. package/libs/apple/libskia.xcframework/ios-arm64_arm64e/libskia.a +0 -0
  100. package/libs/apple/libskia.xcframework/ios-arm64_arm64e_x86_64-simulator/libskia.a +0 -0
  101. package/libs/apple/libskia.xcframework/macos-arm64_x86_64/libskia.a +0 -0
  102. package/libs/apple/libskia.xcframework/tvos-arm64_arm64e/libskia.a +0 -0
  103. package/libs/apple/libskia.xcframework/tvos-arm64_arm64e_x86_64-simulator/libskia.a +0 -0
  104. package/libs/apple/libskottie.xcframework/Info.plist +36 -3
  105. package/libs/apple/libskottie.xcframework/ios-arm64_arm64e/libskottie.a +0 -0
  106. package/libs/apple/libskottie.xcframework/ios-arm64_arm64e_x86_64-simulator/libskottie.a +0 -0
  107. package/libs/apple/libskottie.xcframework/macos-arm64_x86_64/libskottie.a +0 -0
  108. package/libs/apple/libskottie.xcframework/tvos-arm64_arm64e/libskottie.a +0 -0
  109. package/libs/apple/libskottie.xcframework/tvos-arm64_arm64e_x86_64-simulator/libskottie.a +0 -0
  110. package/libs/apple/libskparagraph.xcframework/Info.plist +40 -7
  111. package/libs/apple/libskparagraph.xcframework/ios-arm64_arm64e/libskparagraph.a +0 -0
  112. package/libs/apple/libskparagraph.xcframework/ios-arm64_arm64e_x86_64-simulator/libskparagraph.a +0 -0
  113. package/libs/apple/libskparagraph.xcframework/macos-arm64_x86_64/libskparagraph.a +0 -0
  114. package/libs/apple/libskparagraph.xcframework/tvos-arm64_arm64e/libskparagraph.a +0 -0
  115. package/libs/apple/libskparagraph.xcframework/tvos-arm64_arm64e_x86_64-simulator/libskparagraph.a +0 -0
  116. package/libs/apple/libsksg.xcframework/Info.plist +35 -2
  117. package/libs/apple/libsksg.xcframework/ios-arm64_arm64e/libsksg.a +0 -0
  118. package/libs/apple/libsksg.xcframework/ios-arm64_arm64e_x86_64-simulator/libsksg.a +0 -0
  119. package/libs/apple/libsksg.xcframework/macos-arm64_x86_64/libsksg.a +0 -0
  120. package/libs/apple/libsksg.xcframework/tvos-arm64_arm64e/libsksg.a +0 -0
  121. package/libs/apple/libsksg.xcframework/tvos-arm64_arm64e_x86_64-simulator/libsksg.a +0 -0
  122. package/libs/apple/libskshaper.xcframework/Info.plist +33 -0
  123. package/libs/apple/libskshaper.xcframework/ios-arm64_arm64e/libskshaper.a +0 -0
  124. package/libs/apple/libskshaper.xcframework/ios-arm64_arm64e_x86_64-simulator/libskshaper.a +0 -0
  125. package/libs/apple/libskshaper.xcframework/macos-arm64_x86_64/libskshaper.a +0 -0
  126. package/libs/apple/libskshaper.xcframework/tvos-arm64_arm64e/libskshaper.a +0 -0
  127. package/libs/apple/libskshaper.xcframework/tvos-arm64_arm64e_x86_64-simulator/libskshaper.a +0 -0
  128. package/libs/apple/libskunicode_core.xcframework/Info.plist +36 -3
  129. package/libs/apple/libskunicode_core.xcframework/ios-arm64_arm64e/libskunicode_core.a +0 -0
  130. package/libs/apple/libskunicode_core.xcframework/ios-arm64_arm64e_x86_64-simulator/libskunicode_core.a +0 -0
  131. package/libs/apple/libskunicode_core.xcframework/macos-arm64_x86_64/libskunicode_core.a +0 -0
  132. package/libs/apple/libskunicode_core.xcframework/tvos-arm64_arm64e/libskunicode_core.a +0 -0
  133. package/libs/apple/libskunicode_core.xcframework/tvos-arm64_arm64e_x86_64-simulator/libskunicode_core.a +0 -0
  134. package/libs/apple/libskunicode_libgrapheme.xcframework/Info.plist +35 -2
  135. package/libs/apple/libskunicode_libgrapheme.xcframework/ios-arm64_arm64e/libskunicode_libgrapheme.a +0 -0
  136. package/libs/apple/libskunicode_libgrapheme.xcframework/ios-arm64_arm64e_x86_64-simulator/libskunicode_libgrapheme.a +0 -0
  137. package/libs/apple/libskunicode_libgrapheme.xcframework/macos-arm64_x86_64/libskunicode_libgrapheme.a +0 -0
  138. package/libs/apple/libskunicode_libgrapheme.xcframework/tvos-arm64_arm64e/libskunicode_libgrapheme.a +0 -0
  139. package/libs/apple/libskunicode_libgrapheme.xcframework/tvos-arm64_arm64e_x86_64-simulator/libskunicode_libgrapheme.a +0 -0
  140. package/libs/apple/libsvg.xcframework/Info.plist +36 -3
  141. package/libs/apple/libsvg.xcframework/ios-arm64_arm64e/libsvg.a +0 -0
  142. package/libs/apple/libsvg.xcframework/ios-arm64_arm64e_x86_64-simulator/libsvg.a +0 -0
  143. package/libs/apple/libsvg.xcframework/macos-arm64_x86_64/libsvg.a +0 -0
  144. package/libs/apple/libsvg.xcframework/tvos-arm64_arm64e/libsvg.a +0 -0
  145. package/libs/apple/libsvg.xcframework/tvos-arm64_arm64e_x86_64-simulator/libsvg.a +0 -0
  146. package/package.json +1 -1
  147. package/react-native-skia.podspec +2 -2
  148. package/src/__tests__/snapshots/animated-images/bird.png +0 -0
  149. package/src/__tests__/snapshots/demos/product.png +0 -0
  150. package/src/__tests__/snapshots/demos/product2.png +0 -0
  151. package/src/__tests__/snapshots/images/bundle-android.png +0 -0
  152. package/src/__tests__/snapshots/images/bundle-ios.png +0 -0
  153. package/src/__tests__/snapshots/images/bundle-node.png +0 -0
  154. package/src/__tests__/snapshots/images/filter.png +0 -0
  155. package/src/dom/types/Drawings.ts +3 -0
  156. package/src/dom/types/Shaders.ts +2 -4
  157. package/src/renderer/__tests__/e2e/Text.spec.tsx +1 -1
  158. package/src/renderer/components/image/ImageShader.tsx +2 -15
  159. package/src/skia/types/Canvas.ts +2 -3
  160. package/src/skia/types/Image/Image.ts +14 -0
  161. package/src/skia/types/Picture/PictureRecorder.ts +2 -1
  162. package/src/skia/web/JsiSkCanvas.ts +50 -29
  163. package/src/sksg/Container.ts +64 -67
  164. package/src/sksg/HostConfig.ts +4 -9
  165. package/src/sksg/Reconciler.ts +3 -3
  166. package/src/sksg/Recorder/Recorder.ts +20 -0
  167. package/src/sksg/Recorder/commands/Drawing.ts +33 -4
  168. package/src/sksg/Recorder/commands/Shaders.ts +21 -8
  169. package/lib/commonjs/sksg/Recorder/Recording.d.ts +0 -7
  170. package/lib/commonjs/sksg/Recorder/Recording.js +0 -12
  171. package/lib/commonjs/sksg/Recorder/Recording.js.map +0 -1
  172. package/lib/module/sksg/Recorder/Recording.d.ts +0 -7
  173. package/lib/module/sksg/Recorder/Recording.js +0 -5
  174. package/lib/module/sksg/Recorder/Recording.js.map +0 -1
  175. package/lib/typescript/lib/commonjs/sksg/Recorder/Recording.d.ts +0 -5
  176. package/lib/typescript/lib/module/sksg/Recorder/Recording.d.ts +0 -4
  177. package/lib/typescript/src/sksg/Recorder/Recording.d.ts +0 -7
  178. package/src/sksg/Recorder/Recording.ts +0 -13
@@ -17,6 +17,7 @@ import type {
17
17
  SkRect,
18
18
  SkRSXform,
19
19
  SkColor,
20
+ SamplingOptions,
20
21
  } from "../../skia/types";
21
22
 
22
23
  import type {
@@ -37,6 +38,7 @@ export type ImageProps = DrawingNodeProps &
37
38
  RectDef & {
38
39
  fit?: Fit;
39
40
  image: SkImage | null;
41
+ sampling?: SamplingOptions;
40
42
  };
41
43
 
42
44
  export type CircleProps = CircleDef & DrawingNodeProps;
@@ -65,6 +67,7 @@ export interface AtlasProps extends DrawingNodeProps {
65
67
  sprites: SkRect[];
66
68
  transforms: SkRSXform[];
67
69
  colors?: SkColor[];
70
+ sampling?: SamplingOptions;
68
71
  }
69
72
 
70
73
  export interface CubicBezierHandle {
@@ -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,23 +1,21 @@
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
20
  //console.log(recording.commands);
23
21
  replay(ctx, recording.commands);
@@ -25,84 +23,83 @@ const drawOnscreen = (Skia: Skia, nativeId: number, recording: Recording) => {
25
23
  //const end = performance.now();
26
24
  //console.log("Recording time: ", end - start);
27
25
  SkiaViewApi.setJsiProperty(nativeId, "picture", picture);
26
+ rec.dispose();
27
+ picture.dispose();
28
28
  };
29
29
 
30
- export class Container {
31
- private _root: Node[] = [];
32
- private _recording: Recording | null = null;
33
- public unmounted = false;
34
-
35
- private values = new Set<SharedValue<unknown>>();
36
- private mapperId: number | null = null;
37
-
38
- constructor(public Skia: Skia, private nativeId: number) {}
30
+ export abstract class Container {
31
+ public root: Node[] = [];
32
+ protected recording: Recording | null = null;
39
33
 
40
- get root() {
41
- return this._root;
42
- }
34
+ constructor(protected Skia: Skia, protected nativeId: number) {}
43
35
 
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));
36
+ drawOnCanvas(canvas: SkCanvas) {
37
+ if (!this.recording) {
38
+ throw new Error("No recording to draw");
55
39
  }
56
- this._root = root;
57
- const recorder = new Recorder();
58
- visit(recorder, root);
59
- this._recording = createRecording(recorder.commands);
40
+ const ctx = createDrawingContext(
41
+ this.Skia,
42
+ this.recording.paintPool,
43
+ canvas
44
+ );
45
+ //console.log(this._recording);
46
+ replay(ctx, this.recording.commands);
60
47
  }
61
48
 
62
- clear() {
63
- console.log("clear container");
49
+ abstract redraw(): void;
50
+ }
51
+
52
+ class StaticContainer extends Container {
53
+ constructor(Skia: Skia, nativeId: number) {
54
+ super(Skia, nativeId);
64
55
  }
65
56
 
66
57
  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
- })();
58
+ const recorder = new Recorder();
59
+ visit(recorder, this.root);
60
+ this.recording = recorder.getRecording();
61
+ const isOnScreen = this.nativeId !== -1;
62
+ if (isOnScreen) {
63
+ const rec = this.Skia.PictureRecorder();
64
+ const canvas = rec.beginRecording();
65
+ this.drawOnCanvas(canvas);
66
+ const picture = rec.finishRecordingAsPicture();
67
+ SkiaViewApi.setJsiProperty(this.nativeId, "picture", picture);
73
68
  }
74
69
  }
70
+ }
75
71
 
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
- }
72
+ class ReanimatedContainer extends Container {
73
+ private mapperId: number | null = null;
87
74
 
88
- registerValues(values: object) {
89
- Object.values(values)
90
- .filter(isSharedValue)
91
- .forEach((value) => {
92
- this.values.add(value);
93
- });
75
+ constructor(Skia: Skia, nativeId: number) {
76
+ super(Skia, nativeId);
94
77
  }
95
78
 
96
- drawOnCanvas(canvas: SkCanvas) {
97
- if (!this._recording) {
98
- throw new Error("No recording to draw");
79
+ redraw() {
80
+ if (this.mapperId !== null) {
81
+ Rea.stopMapper(this.mapperId);
82
+ }
83
+ const recorder = new Recorder();
84
+ visit(recorder, this.root);
85
+ const record = recorder.getRecording();
86
+ const { animationValues } = record;
87
+ this.recording = {
88
+ commands: record.commands,
89
+ paintPool: record.paintPool,
90
+ };
91
+ if (animationValues.size > 0) {
92
+ const { nativeId, Skia, recording } = this;
93
+ this.mapperId = Rea.startMapper(() => {
94
+ "worklet";
95
+ drawOnscreen(Skia, nativeId, recording!);
96
+ }, Array.from(animationValues));
99
97
  }
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
98
  }
108
99
  }
100
+
101
+ export const createContainer = (Skia: Skia, nativeId: number) => {
102
+ return HAS_REANIMATED_3 && nativeId !== -1
103
+ ? new ReanimatedContainer(Skia, nativeId)
104
+ : new StaticContainer(Skia, nativeId);
105
+ };
@@ -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
  });
@@ -30,12 +30,31 @@ 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
+ animationValues: Set<SharedValue<unknown>> = new Set();
50
+
51
+ getRecording(): Recording & AnimationValues {
52
+ return {
53
+ commands: this.commands,
54
+ paintPool: [],
55
+ animationValues: this.animationValues,
56
+ };
57
+ }
39
58
 
40
59
  private processProps(props: Record<string, unknown>) {
41
60
  const animatedProps: Record<string, SharedValue<unknown>> = {};
@@ -44,6 +63,7 @@ export class Recorder {
44
63
  for (const key in props) {
45
64
  const prop = props[key];
46
65
  if (isSharedValue(prop)) {
66
+ this.animationValues.add(prop);
47
67
  props[key] = prop.value;
48
68
  animatedProps[key] = prop;
49
69
  hasAnimatedProps = true;
@@ -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
 
@@ -19,9 +19,11 @@ import type {
19
19
  TurbulenceProps,
20
20
  TwoPointConicalGradientProps,
21
21
  } from "../../../dom/types";
22
+ import type { SkShader } from "../../../skia/types";
22
23
  import {
23
24
  BlendMode,
24
25
  FilterMode,
26
+ isCubicSampling,
25
27
  MipmapMode,
26
28
  processUniforms,
27
29
  TileMode,
@@ -179,7 +181,7 @@ const declareTurbulenceShader = (
179
181
 
180
182
  const declareImageShader = (ctx: DrawingContext, props: ImageShaderProps) => {
181
183
  "worklet";
182
- const { fit, image, tx, ty, fm, mm, ...imageShaderProps } = props;
184
+ const { fit, image, tx, ty, sampling, ...imageShaderProps } = props;
183
185
  if (!image) {
184
186
  return;
185
187
  }
@@ -199,13 +201,24 @@ const declareImageShader = (ctx: DrawingContext, props: ImageShaderProps) => {
199
201
  const lm = ctx.Skia.Matrix();
200
202
  lm.concat(m3);
201
203
  processTransformProps(lm, imageShaderProps);
202
- const shader = image.makeShaderOptions(
203
- TileMode[enumKey(tx)],
204
- TileMode[enumKey(ty)],
205
- FilterMode[enumKey(fm)],
206
- MipmapMode[enumKey(mm)],
207
- lm
208
- );
204
+ let shader: SkShader;
205
+ if (sampling && isCubicSampling(sampling)) {
206
+ shader = image.makeShaderCubic(
207
+ TileMode[enumKey(tx)],
208
+ TileMode[enumKey(ty)],
209
+ sampling.B,
210
+ sampling.C,
211
+ lm
212
+ );
213
+ } else {
214
+ shader = image.makeShaderCubic(
215
+ TileMode[enumKey(tx)],
216
+ TileMode[enumKey(ty)],
217
+ sampling?.filter ?? FilterMode.Linear,
218
+ sampling?.mipmap ?? MipmapMode.None,
219
+ lm
220
+ );
221
+ }
209
222
  ctx.shaders.push(shader);
210
223
  };
211
224